agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list 550+ messages / 2 participants [nested] [flat]
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) 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 7bf477e0c3f..94819961787 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 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH] Collapse consecutive .** accessors for jsonpath exists queries @ 2026-06-18 20:30 Andrey Rachitskiy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Rachitskiy @ 2026-06-18 20:30 UTC (permalink / raw) When a jsonpath expression contains multiple consecutive .** (jpiAny) accessors, each one triggers a full subtree traversal in executeAnyItem(). k consecutive .** operators can degrade performance to O(N^k) on a document with N nodes, even though a chain like $.**.**.** is redundant for existence semantics and equivalent to a single $.** with merged level bounds. This was reported as a performance problem when expressions such as $.**.**.**.**.* are evaluated with @? against deeply nested JSON: the same query without the trailing .* completes in sub-millisecond time, while the form with redundant .** segments can run for many minutes. A similar pattern in strict mode can also provoke very large memory allocation attempts. Collapse consecutive jpiAny nodes at execution time for existence queries (@? and jsonb_path_exists), merging their level bounds and performing a single executeAnyItem() pass. Author: Andrey Rachitskiy <[email protected]> Reported-by: Andrey Rachitskiy <[email protected]> Backpatch-through: 15 --- src/backend/utils/adt/jsonpath_exec.c | 47 +++++++++++++++++++--- .../src/test/regress/expected/jsonb_jsonpath.out | 40 ++++++++++++++++++ src/test/regress/sql/jsonb_jsonpath.sql | 11 +++++ 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index ba9bbb6..74fc499 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -107,6 +107,8 @@ typedef struct JsonPathExecContext * ignored */ bool throwErrors; /* with "false" all suppressible errors are * suppressed */ + bool existsOnly; /* @? / jsonb_path_exists: may collapse + * redundant consecutive .** accessors */ bool useTz; } JsonPathExecContext; @@ -199,6 +201,7 @@ static JsonPathExecResult executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found, uint32 level, uint32 first, uint32 last, bool ignoreStructuralErrors, bool unwrapNext); +static uint32 mergeAnyBound(uint32 a, uint32 b); static JsonPathBool executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb, bool unwrapRightArg, @@ -567,6 +570,7 @@ executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors, cxt.lastGeneratedObjectId = vars ? 2 : 1; cxt.innermostArraySize = -1; cxt.throwErrors = throwErrors; + cxt.existsOnly = (result == NULL); cxt.useTz = useTz; if (jspStrictAbsenseOfErrors(&cxt) && !result) @@ -920,16 +924,37 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, case jpiAny: { - bool hasNext = jspGetNext(jsp, &elem); + JsonPathItem elem; + bool hasNext; + uint32 first; + uint32 last; + + hasNext = jspGetNext(jsp, &elem); + first = jsp->content.anybounds.first; + last = jsp->content.anybounds.last; + + /* + * Consecutive .** accessors are redundant for existence + * queries and multiply traversal cost. + */ + if (cxt->existsOnly) + { + while (hasNext && elem.type == jpiAny) + { + first = mergeAnyBound(first, elem.content.anybounds.first); + last = mergeAnyBound(last, elem.content.anybounds.last); + hasNext = jspGetNext(&elem, &elem); + } + } /* first try without any intermediate steps */ - if (jsp->content.anybounds.first == 0) + if (first == 0) { bool savedIgnoreStructuralErrors; savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; cxt->ignoreStructuralErrors = true; - res = executeNextItem(cxt, jsp, &elem, + res = executeNextItem(cxt, jsp, hasNext ? &elem : NULL, jb, found, true); cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; @@ -942,8 +967,8 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, (cxt, hasNext ? &elem : NULL, jb->val.binary.data, found, 1, - jsp->content.anybounds.first, - jsp->content.anybounds.last, + first, + last, true, jspAutoUnwrap(cxt)); break; } @@ -1373,6 +1398,18 @@ executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, return res; } + +/* + * Merge level bounds of two consecutive .** accessors. + */ +static uint32 +mergeAnyBound(uint32 a, uint32 b) +{ + if (a == PG_UINT32_MAX || b == PG_UINT32_MAX) + return PG_UINT32_MAX; + return a + b; +} + /* * Implementation of several jsonpath nodes: * - jpiAny (.** accessor), diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index eafb421..5e1bd19 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -792,6 +792,46 @@ select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**{2 to 3}.b ? ( @ > 0)'; t (1 row) +-- Redundant consecutive .** accessors are collapsed for existence queries +-- (@? and jsonb_path_exists), avoiding multiplicative traversal cost. +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.b ? (@ > 0)'; + ?column? +---------- + t +(1 row) + +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.**.b ? (@ > 0)'; + ?column? +---------- + t +(1 row) + +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.**.b ? (@ > 99)'; + ?column? +---------- + f +(1 row) + +select jsonb_path_exists('{"a": {"c": {"b": 1}}}', '$.**.**.b ? (@ > 0)'); + jsonb_path_exists +------------------- + t +(1 row) + +select ('[' || repeat('[', 50) || '0' || repeat(']', 50) || ']')::jsonb + @? 'lax $.**.**.**.**'; + ?column? +---------- + t +(1 row) + +select ('[' || repeat('[', 50) || '0' || repeat(']', 50) || ']')::jsonb + @? 'strict $.**.**.**'; + ?column? +---------- + t +(1 row) + select jsonb_path_query('{"g": {"x": 2}}', '$.g ? (exists (@.x))'); jsonb_path_query ------------------ diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index 8163fc6..4c62fe2 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -155,6 +155,17 @@ select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**{0 to last}.b ? ( @ > 0)'; select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**{1 to last}.b ? ( @ > 0)'; select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**{1 to 2}.b ? ( @ > 0)'; select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**{2 to 3}.b ? ( @ > 0)'; +-- Redundant consecutive .** accessors are collapsed for existence queries +-- (@? and jsonb_path_exists), avoiding multiplicative traversal cost. +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.b ? (@ > 0)'; +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.**.b ? (@ > 0)'; +select jsonb '{"a": {"c": {"b": 1}}}' @? '$.**.**.b ? (@ > 99)'; +select jsonb_path_exists('{"a": {"c": {"b": 1}}}', '$.**.**.b ? (@ > 0)'); +select ('[' || repeat('[', 50) || '0' || repeat(']', 50) || ']')::jsonb + @? 'lax $.**.**.**.**'; +select ('[' || repeat('[', 50) || '0' || repeat(']', 50) || ']')::jsonb + @? 'strict $.**.**.**'; + select jsonb_path_query('{"g": {"x": 2}}', '$.g ? (exists (@.x))'); select jsonb_path_query('{"g": {"x": 2}}', '$.g ? (exists (@.y))'); -- 2.47.3 --MP_/BlgiDE/t55y8Vb7V2uvNybc Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0001-collapse-consecutive-jsonpath-any-pg16.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
end of thread, other threads:[~2026-06-18 20:30 UTC | newest] Thread overview: 550+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-06-18 20:30 [PATCH] Collapse consecutive .** accessors for jsonpath exists queries Andrey Rachitskiy <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox