Skip to content

Commit 2e616de

Browse files
committed
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
1 parent 1b76168 commit 2e616de

File tree

1 file changed

+40
-18
lines changed
  • src/backend/utils/adt

1 file changed

+40
-18
lines changed

src/backend/utils/adt/xml.c

+40-18
Original file line numberDiff line numberDiff line change
@@ -3720,35 +3720,57 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
37203720

37213721
if (cur->type != XML_ATTRIBUTE_NODE && cur->type != XML_TEXT_NODE)
37223722
{
3723-
xmlBufferPtr buf;
3724-
xmlNodePtr cur_copy;
3723+
void (*nodefree) (xmlNodePtr) = NULL;
3724+
volatile xmlBufferPtr buf = NULL;
3725+
volatile xmlNodePtr cur_copy = NULL;
37253726

3726-
buf = xmlBufferCreate();
3727+
PG_TRY();
3728+
{
3729+
int bytes;
37273730

3728-
/*
3729-
* The result of xmlNodeDump() won't contain namespace definitions
3730-
* from parent nodes, but xmlCopyNode() duplicates a node along with
3731-
* its required namespace definitions.
3732-
*/
3733-
cur_copy = xmlCopyNode(cur, 1);
3731+
buf = xmlBufferCreate();
3732+
if (buf == NULL || xmlerrcxt->err_occurred)
3733+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
3734+
"could not allocate xmlBuffer");
37343735

3735-
if (cur_copy == NULL)
3736-
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
3737-
"could not copy node");
3736+
/*
3737+
* Produce a dump of the node that we can serialize. xmlNodeDump
3738+
* does that, but the result of that function won't contain
3739+
* namespace definitions from ancestor nodes, so we first do a
3740+
* xmlCopyNode() which duplicates the node along with its required
3741+
* namespace definitions.
3742+
*
3743+
* Some old libxml2 versions such as 2.7.6 produce partially
3744+
* broken XML_DOCUMENT_NODE nodes (unset content field) when
3745+
* copying them. xmlNodeDump of such a node works fine, but
3746+
* xmlFreeNode crashes; set us up to call xmlFreeDoc instead.
3747+
*/
3748+
cur_copy = xmlCopyNode(cur, 1);
3749+
if (cur_copy == NULL || xmlerrcxt->err_occurred)
3750+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
3751+
"could not copy node");
3752+
nodefree = (cur_copy->type == XML_DOCUMENT_NODE) ?
3753+
(void (*) (xmlNodePtr)) xmlFreeDoc : xmlFreeNode;
3754+
3755+
bytes = xmlNodeDump(buf, NULL, cur_copy, 0, 1);
3756+
if (bytes == -1 || xmlerrcxt->err_occurred)
3757+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
3758+
"could not dump node");
37383759

3739-
PG_TRY();
3740-
{
3741-
xmlNodeDump(buf, NULL, cur_copy, 0, 1);
37423760
result = xmlBuffer_to_xmltype(buf);
37433761
}
37443762
PG_CATCH();
37453763
{
3746-
xmlFreeNode(cur_copy);
3747-
xmlBufferFree(buf);
3764+
if (nodefree)
3765+
nodefree(cur_copy);
3766+
if (buf)
3767+
xmlBufferFree(buf);
37483768
PG_RE_THROW();
37493769
}
37503770
PG_END_TRY();
3751-
xmlFreeNode(cur_copy);
3771+
3772+
if (nodefree)
3773+
nodefree(cur_copy);
37523774
xmlBufferFree(buf);
37533775
}
37543776
else

0 commit comments

Comments
 (0)