From 7f0302c0e4a74b3ec3f497c00a7f853c1e0fbbd3 Mon Sep 17 00:00:00 2001 From: Andrey Chernyy Date: Mon, 25 May 2026 22:12:02 +0300 Subject: [PATCH v2 1/3] Fix libxml string leak in contrib/xml2 xpath_list xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f2..94819961787e 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0