diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-03-08 19:13:25 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2019-03-08 19:13:25 -0300 |
commit | 2e616dee9e601d36462dc4cc48eb0b6a1ff20051 (patch) | |
tree | 3995a7ebfb094370d62a0bb908ddb71391a04c8b /src/backend/utils/adt/xml.c | |
parent | 1b76168da7787505fbe506ef3ab74e9a14b4b7fb (diff) | |
download | postgresql-2e616dee9e601d36462dc4cc48eb0b6a1ff20051.tar.gz postgresql-2e616dee9e601d36462dc4cc48eb0b6a1ff20051.zip |
Fix crash with old libxml2
Certain libxml2 versions (such as the 2.7.6 commonly seen in older
distributions, but apparently only on x86_64) contain a bug that causes
xmlCopyNode, when called on a XML_DOCUMENT_NODE, to return a node that
xmlFreeNode crashes on. Arrange to call xmlFreeDoc instead of
xmlFreeNode for those nodes.
Per buildfarm members lapwing and grison.
Author: Pavel Stehule, light editing by Álvaro.
Discussion: https://postgr.es/m/20190308024436.GA2374@alvherre.pgsql
Diffstat (limited to 'src/backend/utils/adt/xml.c')
-rw-r--r-- | src/backend/utils/adt/xml.c | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 28b3eaaa201..1116b773427 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -3720,35 +3720,57 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt) if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE) { - xmlBufferPtr buf; - xmlNodePtr cur_copy; + void (*nodefree) (xmlNodePtr) = NULL; + volatile xmlBufferPtr buf = NULL; + volatile xmlNodePtr cur_copy = NULL; - buf = xmlBufferCreate(); + PG_TRY(); + { + int bytes; - /* - * The result of xmlNodeDump() won't contain namespace definitions - * from parent nodes, but xmlCopyNode() duplicates a node along with - * its required namespace definitions. - */ - cur_copy = xmlCopyNode(cur, 1); + buf = xmlBufferCreate(); + if (buf == NULL || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xmlBuffer"); - if (cur_copy == NULL) - xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, - "could not copy node"); + /* + * Produce a dump of the node that we can serialize. xmlNodeDump + * does that, but the result of that function won't contain + * namespace definitions from ancestor nodes, so we first do a + * xmlCopyNode() which duplicates the node along with its required + * namespace definitions. + * + * Some old libxml2 versions such as 2.7.6 produce partially + * broken XML_DOCUMENT_NODE nodes (unset content field) when + * copying them. xmlNodeDump of such a node works fine, but + * xmlFreeNode crashes; set us up to call xmlFreeDoc instead. + */ + cur_copy = xmlCopyNode(cur, 1); + if (cur_copy == NULL || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not copy node"); + nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ? + (void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode; + + bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 1); + if (bytes == -1 || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not dump node"); - PG_TRY(); - { - xmlNodeDump(buf, NULL, cur_copy, 0, 1); result = xmlBuffer_to_xmltype(buf); } PG_CATCH(); { - xmlFreeNode(cur_copy); - xmlBufferFree(buf); + if (nodefree) + nodefree(cur_copy); + if (buf) + xmlBufferFree(buf); PG_RE_THROW(); } PG_END_TRY(); - xmlFreeNode(cur_copy); + + if (nodefree) + nodefree(cur_copy); xmlBufferFree(buf); } else |