agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v3 1/3] Adding per backend commit and rollback counters 550+ messages / 2 participants [nested] [flat]
* [PATCH v3 1/3] Adding per backend commit and rollback counters @ 2025-08-04 08:14 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Bertrand Drouvot @ 2025-08-04 08:14 UTC (permalink / raw) It relies on the existing per backend statistics that has been added in 9aea73fc61d. A new function is called in AtEOXact_PgStat() to increment those two new counters. --- src/backend/utils/activity/pgstat_backend.c | 57 +++++++++++++++++++++ src/backend/utils/activity/pgstat_xact.c | 1 + src/include/pgstat.h | 8 +++ src/include/utils/pgstat_internal.h | 4 +- 4 files changed, 69 insertions(+), 1 deletion(-) 78.9% src/backend/utils/activity/ 11.2% src/include/utils/ 9.8% src/include/ diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c index 8714a85e2d9..bf164854c4b 100644 --- a/src/backend/utils/activity/pgstat_backend.c +++ b/src/backend/utils/activity/pgstat_backend.c @@ -47,6 +47,11 @@ static bool backend_has_iostats = false; */ static WalUsage prevBackendWalUsage; +/* + * For backend commit and rollback statistics. + */ +static bool backend_has_xactstats = false; + /* * Utility routines to report I/O stats for backends, kept here to avoid * exposing PendingBackendStats to the outside world. @@ -259,6 +264,34 @@ pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref) prevBackendWalUsage = pgWalUsage; } +/* + * Flush out locally pending backend transaction statistics. Locking is managed + * by the caller. + */ +static void +pgstat_flush_backend_entry_xact(PgStat_EntryRef *entry_ref) +{ + PgStatShared_Backend *shbackendent; + + /* + * This function can be called even if nothing at all has happened for + * transaction statistics. In this case, avoid unnecessarily modifying + * the stats entry. + */ + if (!backend_has_xactstats) + return; + + shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats; + + shbackendent->stats.xact_commit += PendingBackendStats.pending_xact_commit; + shbackendent->stats.xact_rollback += PendingBackendStats.pending_xact_rollback; + + PendingBackendStats.pending_xact_commit = 0; + PendingBackendStats.pending_xact_rollback = 0; + + backend_has_xactstats = false; +} + /* * Flush out locally pending backend statistics * @@ -283,6 +316,10 @@ pgstat_flush_backend(bool nowait, bits32 flags) pgstat_backend_wal_have_pending()) has_pending_data = true; + /* Some transaction data pending? */ + if ((flags & PGSTAT_BACKEND_FLUSH_XACT) && backend_has_xactstats) + has_pending_data = true; + if (!has_pending_data) return false; @@ -298,6 +335,9 @@ pgstat_flush_backend(bool nowait, bits32 flags) if (flags & PGSTAT_BACKEND_FLUSH_WAL) pgstat_flush_backend_entry_wal(entry_ref); + if (flags & PGSTAT_BACKEND_FLUSH_XACT) + pgstat_flush_backend_entry_xact(entry_ref); + pgstat_unlock_entry(entry_ref); return false; @@ -400,3 +440,20 @@ pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts) { ((PgStatShared_Backend *) header)->stats.stat_reset_timestamp = ts; } + +void +AtEOXact_PgStat_Backend(bool isCommit, bool parallel) +{ + /* Don't count parallel worker transaction stats */ + if (!parallel) + { + /* Count transaction commit or abort */ + if (isCommit) + PendingBackendStats.pending_xact_commit++; + else + PendingBackendStats.pending_xact_rollback++; + + backend_has_xactstats = true; + pgstat_report_fixed = true; + } +} diff --git a/src/backend/utils/activity/pgstat_xact.c b/src/backend/utils/activity/pgstat_xact.c index bc9864bd8d9..cd1c501c165 100644 --- a/src/backend/utils/activity/pgstat_xact.c +++ b/src/backend/utils/activity/pgstat_xact.c @@ -42,6 +42,7 @@ AtEOXact_PgStat(bool isCommit, bool parallel) PgStat_SubXactStatus *xact_state; AtEOXact_PgStat_Database(isCommit, parallel); + AtEOXact_PgStat_Backend(isCommit, parallel); /* handle transactional stats information */ xact_state = pgStatXactStack; diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 202bd2d5ace..9efc0e10ebf 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -490,6 +490,8 @@ typedef struct PgStat_Backend TimestampTz stat_reset_timestamp; PgStat_BktypeIO io_stats; PgStat_WalCounters wal_counters; + PgStat_Counter xact_commit; + PgStat_Counter xact_rollback; } PgStat_Backend; /* --------- @@ -502,6 +504,12 @@ typedef struct PgStat_BackendPending * Backend statistics store the same amount of IO data as PGSTAT_KIND_IO. */ PgStat_PendingIO pending_io; + + /* + * Transaction statistics pending flush. + */ + PgStat_Counter pending_xact_commit; + PgStat_Counter pending_xact_rollback; } PgStat_BackendPending; /* diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h index 6cf00008f63..23ea8ffd618 100644 --- a/src/include/utils/pgstat_internal.h +++ b/src/include/utils/pgstat_internal.h @@ -616,12 +616,14 @@ extern void pgstat_archiver_snapshot_cb(void); /* flags for pgstat_flush_backend() */ #define PGSTAT_BACKEND_FLUSH_IO (1 << 0) /* Flush I/O statistics */ #define PGSTAT_BACKEND_FLUSH_WAL (1 << 1) /* Flush WAL statistics */ -#define PGSTAT_BACKEND_FLUSH_ALL (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL) +#define PGSTAT_BACKEND_FLUSH_XACT (1 << 2) /* Flush xact statistics */ +#define PGSTAT_BACKEND_FLUSH_ALL (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL | PGSTAT_BACKEND_FLUSH_XACT) extern bool pgstat_flush_backend(bool nowait, bits32 flags); extern bool pgstat_backend_flush_cb(bool nowait); extern void pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts); +extern void AtEOXact_PgStat_Backend(bool isCommit, bool parallel); /* * Functions in pgstat_bgwriter.c -- 2.34.1 --u6+Li7FU79Mt/lVd Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v3-0002-Adding-XID-generation-count-per-backend.patch" ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
* [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list @ 2026-05-25 19:12 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 550+ messages in thread From: Andrey Chernyy @ 2026-05-25 19:12 UTC (permalink / raw) xmlXPathCastNodeToString() returns a libxml-allocated xmlChar *, but pgxmlNodeSetToText() passed it directly to xmlBufferWriteCHAR() in the plain separator path. Since xmlBufferWriteCHAR() copies the string rather than taking ownership, successful xpath_list() calls leaked one string per emitted node. Store the cast result locally and free it with xmlFree() after writing it to the buffer. --- contrib/xml2/xpath.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 7bf477e0c3f..94819961787 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -147,6 +147,7 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { volatile xmlBufferPtr buf = NULL; xmlChar *volatile result = NULL; + xmlChar *volatile str = NULL; PgXmlErrorContext *xmlerrcxt; /* spin up some error handling */ @@ -172,8 +173,14 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, { if (plainsep != NULL) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); + str = xmlXPathCastNodeToString(nodeset->nodeTab[i]); + if (str == NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate node text"); + + xmlBufferWriteCHAR(buf, str); + xmlFree(str); + str = NULL; /* If this isn't the last entry, write the plain sep. */ if (i < (nodeset->nodeNr) - 1) @@ -216,6 +223,8 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, } PG_CATCH(); { + if (str) + xmlFree(str); if (buf) xmlBufferFree(buf); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0002-Fix-libxml-leaks-in-contrib-xml2-xpath_table.patch ^ permalink raw reply [nested|flat] 550+ messages in thread
end of thread, other threads:[~2026-05-25 19:12 UTC | newest] Thread overview: 550+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2025-08-04 08:14 [PATCH v3 1/3] Adding per backend commit and rollback counters Bertrand Drouvot <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[email protected]> 2026-05-25 19:12 [PATCH 1/2] Fix libxml string leak in contrib/xml2 xpath_list Andrey Chernyy <[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