Re: [PATCH] Add pretty-printed XML output option - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [PATCH] Add pretty-printed XML output option
Date
Msg-id 1358967.1747858817@sss.pgh.pa.us
Whole thread Raw
In response to Re: [PATCH] Add pretty-printed XML output option  (Jim Jones <jim.jones@uni-muenster.de>)
List pgsql-hackers
Jim Jones <jim.jones@uni-muenster.de> writes:
> In my environment (libxml2 v2.9.10 and Ubuntu 22.04) I couldn't 
> reproduce this memory leak.

Just when you thought it was safe to go back in the water ...

Experimenting with the improved valgrind leak detection code at [1],
I discovered that XMLSERIALIZE(... INDENT) has yet a different memory
leak problem.  It turns out that xmlDocSetRootElement() doesn't
merely install the given root node: it unlinks the document's old
root node and returns it to you.  If you don't free it, it's leaked
(for the session, since this is a malloc not palloc).  The amount of
leakage isn't that large, seems to be a couple hundred bytes per
iteration, which may explain why this escaped our notice in the
previous testing.  Still, it could add up under extensive usage.
So I think we need to apply the attached, back to PG 16.

            regards, tom lane

[1] https://www.postgresql.org/message-id/1295385.1747847681%40sss.pgh.pa.us

diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index db8d0d6a7e8..73fd4fa090c 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -754,6 +754,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
              * content nodes, and then iterate over the nodes.
              */
             xmlNodePtr    root;
+            xmlNodePtr    oldroot;
             xmlNodePtr    newline;

             root = xmlNewNode(NULL, (const xmlChar *) "content-root");
@@ -761,8 +762,14 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
                 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
                             "could not allocate xml node");

-            /* This attaches root to doc, so we need not free it separately. */
-            xmlDocSetRootElement(doc, root);
+            /*
+             * This attaches root to doc, so we need not free it separately...
+             * but instead, we have to free the old root if there was one.
+             */
+            oldroot = xmlDocSetRootElement(doc, root);
+            if (oldroot != NULL)
+                xmlFreeNode(oldroot);
+
             xmlAddChildList(root, content_nodes);

             /*

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: Minor adjustment to pg_aios output naming
Next
From: "David G. Johnston"
Date:
Subject: [Util] Warn and Remove Invalid GUCs