From 6f03bd2f6eb829eb8ece9c1d9df7d3035ac78d92 Mon Sep 17 00:00:00 2001 From: Richard Schwarting Date: Sun, 9 Jun 2013 23:37:46 -0400 Subject: [PATCH] libxml-2.0.vapi, Attr.vala, Document.vala, Element.vala: stop leaking memory from xmlAttrs --- gxml/Attr.vala | 2 +- gxml/Document.vala | 11 ++++++++--- gxml/Element.vala | 16 ++++++++++------ vapi/libxml-2.0.vapi | 3 +++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/gxml/Attr.vala b/gxml/Attr.vala index e0f270d9..2770d7bc 100644 --- a/gxml/Attr.vala +++ b/gxml/Attr.vala @@ -68,7 +68,7 @@ namespace GXml { } /** Private properties */ - private Xml.Attr *node; + internal Xml.Attr *node; /** Constructors */ internal Attr (Xml.Attr *node, Document doc) { diff --git a/gxml/Document.vala b/gxml/Document.vala index af08c2e1..840b18d2 100644 --- a/gxml/Document.vala +++ b/gxml/Document.vala @@ -186,6 +186,8 @@ namespace GXml { ~Document () { List to_free = new List (); + sync_dirty_elements (); + /* we use two separate loops, because freeing a node frees its descendants, and we might have a branch with children that might be @@ -328,10 +330,11 @@ namespace GXml { try { instream = fin.read (null); + this.from_stream (instream, can); + instream.close (); } catch (GLib.Error e) { throw new DomError.INVALID_DOC (e.message); } - this.from_stream (instream, can); } /** * Creates a Document from data provided through the InputStream instream. @@ -342,13 +345,13 @@ namespace GXml { // TODO: accept Cancellable // Cancellable can = new Cancellable (); InputStreamBox box = { instream, can }; - + Xml.Doc *doc; Xml.TextReader reader = new Xml.TextReader.for_io ((Xml.InputReadCallback)_ioread, (Xml.InputCloseCallback)_ioinclose, &box, "", null, 0); reader.read (); reader.expand (); - Xml.Doc *doc = reader.current_doc (); + doc = reader.current_doc (); reader.close (); this.from_libxml2 (doc); @@ -393,6 +396,8 @@ namespace GXml { elem.save_attributes (tmp_node); } this.dirty_elements = new List (); // clear the old list + + tmp_node->free (); } } diff --git a/gxml/Element.vala b/gxml/Element.vala index 1c3ed8ec..0ee8b891 100644 --- a/gxml/Element.vala +++ b/gxml/Element.vala @@ -95,7 +95,7 @@ namespace GXml { if (this._attributes == null) { this.owner_document.dirty_elements.append (this); this._attributes = new HashTable (GLib.str_hash, GLib.str_equal); - // TODO: make sure other HashTables have appropriate hash, equal functions + // TODO: make sure other HashTables have appropriate hash, equal functions for (Xml.Attr *prop = base.node->properties; prop != null; prop = prop->next) { attr = new Attr (prop, this.owner_document); @@ -144,16 +144,21 @@ namespace GXml { } // Go through the GXml table of attributes for this element and add corresponding libxml2 ones - foreach (string propname in this.attributes.get_keys ()) { - attr = this.attributes.lookup (propname); + foreach (string propname in this._attributes.get_keys ()) { + attr = this._attributes.lookup (propname); + Xml.Attr* saved_attr; if (attr.namespace_uri != null || attr.prefix != null) { // I hate namespace handling between libxml2 and DOM Level 2/3 Core! ns = tmp_node->new_ns (attr.namespace_uri, attr.prefix); - this.node->set_ns_prop (ns, propname, attr.node_value); + saved_attr = this.node->set_ns_prop (ns, propname, attr.node_value); } else { - this.node->set_prop (propname, attr.node_value); + saved_attr = this.node->set_prop (propname, attr.node_value); } + + // Replace the old out-of-tree attr with the newly allocated one in the tree, that way xmlFreeDoc can clean up correctly + attr.node->free (); + attr.node = saved_attr; } } } @@ -214,7 +219,6 @@ namespace GXml { this.attributes.replace (name, attr); // TODO: replace wanted 'owned', look up what to do - } /** * Remove the attribute named name from this element. diff --git a/vapi/libxml-2.0.vapi b/vapi/libxml-2.0.vapi index 6743b1c0..b434a7e3 100644 --- a/vapi/libxml-2.0.vapi +++ b/vapi/libxml-2.0.vapi @@ -277,6 +277,9 @@ namespace Xml { public Ns* ns; public AttributeType atype; + [CCode (cname = "xmlFreeProp")] + public int free(); + [CCode (cname = "xmlRemoveProp")] public int remove(); } -- GitLab