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
This commit is contained in:
Alvaro Herrera 2019-03-08 19:13:25 -03:00
parent 1b76168da7
commit 2e616dee9e
1 changed files with 41 additions and 19 deletions

View File

@ -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;
buf = xmlBufferCreate();
/*
* 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);
if (cur_copy == NULL)
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
"could not copy node");
void (*nodefree) (xmlNodePtr) = NULL;
volatile xmlBufferPtr buf = NULL;
volatile xmlNodePtr cur_copy = NULL;
PG_TRY();
{
xmlNodeDump(buf, NULL, cur_copy, 0, 1);
int bytes;
buf = xmlBufferCreate();
if (buf == NULL || xmlerrcxt->err_occurred)
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
"could not allocate xmlBuffer");
/*
* 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");
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