agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table 551+ messages / 1 participants [nested] [flat]
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
* [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table @ 2026-05-25 21:11 Andrey Chernyy <[email protected]> 0 siblings, 0 replies; 551+ messages in thread From: Andrey Chernyy @ 2026-05-25 21:11 UTC (permalink / raw) xpath_table() did not release libxml objects allocated while evaluating XPath expressions. xmlXPathCompiledEval() returns an xmlXPathObjectPtr that must be freed, and string results copied into the tuple input array must be freed after BuildTupleFromCStrings() has consumed them. Track the current libxml objects across the existing PG_TRY block so they are also released on error. --- contrib/xml2/xpath.c | 47 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 94819961787..ac140a640e0 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -643,6 +643,10 @@ xpath_table(PG_FUNCTION_ARGS) StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; + xmlXPathContextPtr volatile ctxt = NULL; + xmlXPathObjectPtr volatile res = NULL; + xmlXPathCompExprPtr volatile comppath = NULL; + xmlChar *volatile resstr = NULL; InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC); @@ -662,7 +666,7 @@ xpath_table(PG_FUNCTION_ARGS) attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc); - values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *)); + values = (char **) palloc0(rsinfo->setDesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(rsinfo->setDesc->natts * sizeof(xmlChar *)); /* @@ -732,10 +736,6 @@ xpath_table(PG_FUNCTION_ARGS) { char *pkey; char *xmldoc; - xmlXPathContextPtr ctxt; - xmlXPathObjectPtr res; - xmlChar *resstr; - xmlXPathCompExprPtr comppath; HeapTuple ret_tuple; /* Extract the row data as C Strings */ @@ -780,6 +780,11 @@ xpath_table(PG_FUNCTION_ARGS) had_values = false; for (j = 0; j < numpaths; j++) { + ctxt = NULL; + res = NULL; + comppath = NULL; + resstr = NULL; + ctxt = xmlXPathNewContext(doctree); if (ctxt == NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, @@ -798,6 +803,7 @@ xpath_table(PG_FUNCTION_ARGS) /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); + comppath = NULL; if (res != NULL) { @@ -842,8 +848,16 @@ xpath_table(PG_FUNCTION_ARGS) * result tuple. */ values[j + 1] = (char *) resstr; + resstr = NULL; + } + + if (res != NULL) + { + xmlXPathFreeObject(res); + res = NULL; } xmlXPathFreeContext(ctxt); + ctxt = NULL; } /* Now add the tuple to the output, if there is one. */ @@ -854,6 +868,16 @@ xpath_table(PG_FUNCTION_ARGS) heap_freetuple(ret_tuple); } + /* BuildTupleFromCStrings() has copied the values. */ + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + { + xmlFree((xmlChar *) values[j]); + values[j] = NULL; + } + } + rownr++; } while (had_values); } @@ -870,6 +894,19 @@ xpath_table(PG_FUNCTION_ARGS) } PG_CATCH(); { + if (resstr != NULL) + xmlFree(resstr); + for (j = 1; j < rsinfo->setDesc->natts; j++) + { + if (values[j] != NULL) + xmlFree((xmlChar *) values[j]); + } + if (res != NULL) + xmlXPathFreeObject(res); + if (comppath != NULL) + xmlXPathFreeCompExpr(comppath); + if (ctxt != NULL) + xmlXPathFreeContext(ctxt); if (doctree != NULL) xmlFreeDoc(doctree); -- 2.54.0 --MP_/T7YUrG7W2jPQOBsjEYwqj9B-- ^ permalink raw reply [nested|flat] 551+ messages in thread
end of thread, other threads:[~2026-05-25 21:11 UTC | newest] Thread overview: 551+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table Andrey Chernyy <[email protected]> 2026-05-25 21:11 [PATCH 2/2] Fix libxml leaks in contrib/xml2 xpath_table 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