After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 768404 - Memory leak when using remove_attribute
Memory leak when using remove_attribute
Status: RESOLVED FIXED
Product: libxml++
Classification: Bindings
Component: General
3.0.x
Other Linux
: Normal normal
: ---
Assigned To: Christophe de Vienne
Christophe de Vienne
Depends on:
Blocks:
 
 
Reported: 2016-07-04 17:30 UTC by Harald Schmalzl
Modified: 2016-07-06 14:46 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Harald Schmalzl 2016-07-04 17:30:27 UTC
Hi!

LeakSanitizer told me that there is a memory leak in libxml++.
Test Program:
___________________________________________________________________
#include <libxml++/libxml++.h>

int main(int , char **)
{
	xmlpp::Document document;
	auto nodeRoot = document.create_root_node("exampleroot");
	auto nodeChild = nodeRoot->add_child_element("examplechild");
	nodeChild->set_attribute("woswasidenn", "bla");
	nodeChild->remove_attribute("woswasidenn");
	return 0;
}
___________________________________________________________________

Command Line to compile the program:
g++ -g -fsanitize=address -std=c++11 $(pkg-config --cflags libxml++-3.0) main.cpp $(pkg-config --libs libxml++-3.0) -lz

Running this prodram produces the following output:
___________________________________________________________________

=================================================================
==4877==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7ff3de780452 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99452)
    #1 0x40a509 in xmlpp::Node::create_wrapper(_xmlNode*) nodes/node.cc:534
    #2 0x6e6e64  (<unknown module>)

SUMMARY: AddressSanitizer: 16 byte(s) leaked in 1 allocation(s).
___________________________________________________________________


I created the following patch to correct the problem:
___________________________________________________________________
diff -Naur libxml++.orig-3.0.0/libxml++/nodes/element.cc libxml++-3.0.0/libxml++/nodes/element.cc
--- libxml++.orig-3.0.0/libxml++/nodes/element.cc	2015-11-05 11:04:56.000000000 +0100
+++ libxml++-3.0.0/libxml++/nodes/element.cc	2016-04-18 13:29:39.250433896 +0200
@@ -134,12 +134,35 @@
 void Element::remove_attribute(const Glib::ustring& name, const Glib::ustring& ns_prefix)
 {
   if (ns_prefix.empty())
+  {
+    xmlAttr *attr = xmlHasProp(cobj(), (const xmlChar*)name.c_str());
+    if (!attr)
+      return;
+    if (attr->type != XML_ATTRIBUTE_DECL)
+    {
+      // *this has an attribute with the same name as the imported attribute.
+      // xmlAddChild() will delete the existing attribute.
+      // Delete the C++ wrapper before the call to xmlAddChild().
+      Node::free_wrappers(reinterpret_cast<xmlNode*>(attr));
+    }
     xmlUnsetProp(cobj(), (const xmlChar*)name.c_str());
+  }
   else
   {
     auto ns = xmlSearchNs(cobj()->doc, cobj(), (const xmlChar*)ns_prefix.c_str());
-    if (ns)
-      xmlUnsetNsProp(cobj(), ns, (const xmlChar*)name.c_str());
+    if (!ns)
+      return;
+    xmlAttr *attr = xmlHasNsProp(cobj(), (const xmlChar*)name.c_str(), (const xmlChar*)ns_prefix.c_str());
+    if (!attr)
+      return;
+    if (attr->type != XML_ATTRIBUTE_DECL)
+    {
+      // *this has an attribute with the same name as the imported attribute.
+      // xmlAddChild() will delete the existing attribute.
+      // Delete the C++ wrapper before the call to xmlAddChild().
+      Node::free_wrappers(reinterpret_cast<xmlNode*>(attr));
+    }
+    xmlUnsetNsProp(cobj(), ns, (const xmlChar*)name.c_str());
   }
 }

___________________________________________________________________


I guess this patch will not meet your standards, but it shows the problematic bits of code.

regards
Comment 1 Kjell Ahlstedt 2016-07-06 14:46:41 UTC
Thanks. I've pushed a patch similar to your patch.
https://git.gnome.org/browse/libxml++/commit/?id=c75f521cefe1d6ded3e6d67397ecbbdde2ce3b48

I made mainly two changes:
1. An obvious flaw in your patch is that the comment that you copied from
   Node::import_node() does not fit here.
2. A much less obvious flaw is that you used xmlHasProp(). It finds an attribute
   with a specified name, regardless of the attribute's namespace, while
   xmlUnsetProp() only removes an attribute with no namespace. Unfortunately
   that's not clear from the documentation of xmlHasProp().