aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/xml.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2019-03-08 19:13:25 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2019-03-08 19:13:25 -0300
commit2e616dee9e601d36462dc4cc48eb0b6a1ff20051 (patch)
tree3995a7ebfb094370d62a0bb908ddb71391a04c8b /src/backend/utils/adt/xml.c
parent1b76168da7787505fbe506ef3ab74e9a14b4b7fb (diff)
downloadpostgresql-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.c58
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