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
pull/39/head
Alvaro Herrera 7 years ago
parent 1b76168da7
commit 2e616dee9e
  1. 58
      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

Loading…
Cancel
Save