diff --git a/ChangeLog b/ChangeLog index 9238dcc6..8143e16a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Mar 12 10:22:01 CET 2008 Daniel Veillard + + * python/types.c: fix a memory errro when using namespace nodes + returned from XPath queries, should fix #521699 + * python/tests/Makefile.am python/tests/xpathns.py: add a specific + regression test for it + Mon Mar 10 16:25:32 CET 2008 Rob Richards * include/win32config.h: add ICONV_CONST define for win32 build diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am index af23af3d..8a850756 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -45,7 +45,8 @@ PYTESTS= \ validDTD.py \ validSchemas.py \ validRNG.py \ - compareNodes.py + compareNodes.py \ + xpathns.py XMLS= \ tst.xml \ diff --git a/python/tests/xpathns.py b/python/tests/xpathns.py new file mode 100755 index 00000000..e67e5506 --- /dev/null +++ b/python/tests/xpathns.py @@ -0,0 +1,29 @@ +#!/usr/bin/python -u +# +import libxml2 + +expect=' xmlns:a="urn:whatevar"' + +# Memory debug specific +libxml2.debugMemory(1) + +d = libxml2.parseDoc("") +res="" +for n in d.xpathEval("//namespace::*"): + res = res + n.serialize() +d.freeDoc() + +if res != expect: + print "test5 failed: unexpected output" + print res +del res +del d +del n +# Memory debug specific +libxml2.cleanupParser() + +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/python/types.c b/python/types.c index 9a17749e..80e43041 100644 --- a/python/types.c +++ b/python/types.c @@ -7,6 +7,7 @@ * daniel@veillard.com */ #include "libxml_wrap.h" +#include PyObject * libxml_intWrap(int val) @@ -330,6 +331,24 @@ libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt) return (ret); } +/** + * libxml_xmlXPathDestructNsNode: + * cobj: xmlNsPtr namespace node + * desc: ignored string + * + * This function is called if and when a namespace node returned in + * an XPath node set is to be destroyed. That's the only kind of + * object returned in node set not directly linked to the original + * xmlDoc document, see xmlXPathNodeSetDupNs. + */ +static void +libxml_xmlXPathDestructNsNode(void *cobj, void *desc ATTRIBUTE_UNUSED) { +#ifdef DEBUG + fprintf(stderr, "libxml_xmlXPathDestructNsNode called %p\n", cobj); +#endif + xmlXPathNodeSetFreeNs((xmlNsPtr) cobj); +} + PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj) { @@ -380,8 +399,17 @@ libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj) ret = PyList_New(obj->nodesetval->nodeNr); for (i = 0; i < obj->nodesetval->nodeNr; i++) { node = obj->nodesetval->nodeTab[i]; - /* TODO: try to cast directly to the proper node type */ - PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node)); + if (node->type == XML_NAMESPACE_DECL) { + PyObject *ns = + PyCObject_FromVoidPtrAndDesc((void *) node, + (char *) "xmlNsPtr", + libxml_xmlXPathDestructNsNode); + PyList_SetItem(ret, i, ns); + /* make sure the xmlNsPtr is not destroyed now */ + obj->nodesetval->nodeTab[i] = NULL; + } else { + PyList_SetItem(ret, i, libxml_xmlNodePtrWrap(node)); + } } } break;