Commit 2e616dee authored by Alvaro Herrera's avatar Alvaro Herrera

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
parent 1b76168d
...@@ -3720,35 +3720,57 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt) ...@@ -3720,35 +3720,57 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE) if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
{ {
xmlBufferPtr buf; void (*nodefree) (xmlNodePtr) = NULL;
xmlNodePtr cur_copy; volatile xmlBufferPtr buf = NULL;
volatile xmlNodePtr cur_copy = NULL;
buf = xmlBufferCreate(); PG_TRY();
{
int bytes;
/* buf = xmlBufferCreate();
* The result of xmlNodeDump() won't contain namespace definitions if (buf == NULL || xmlerrcxt->err_occurred)
* from parent nodes, but xmlCopyNode() duplicates a node along with xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
* its required namespace definitions. "could not allocate xmlBuffer");
*/
cur_copy = xmlCopyNode(cur, 1);
if (cur_copy == NULL) /*
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, * Produce a dump of the node that we can serialize. xmlNodeDump
"could not copy node"); * 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); result = xmlBuffer_to_xmltype(buf);
} }
PG_CATCH(); PG_CATCH();
{ {
xmlFreeNode(cur_copy); if (nodefree)
xmlBufferFree(buf); nodefree(cur_copy);
if (buf)
xmlBufferFree(buf);
PG_RE_THROW(); PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
xmlFreeNode(cur_copy);
if (nodefree)
nodefree(cur_copy);
xmlBufferFree(buf); xmlBufferFree(buf);
} }
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment