[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: [xml] Memory reference after xmlFree in XPath evaluation
- From: Brian Stafford <brian stafford office-logic com>
- To: xml gnome org
- Subject: Re: [xml] Memory reference after xmlFree in XPath evaluation
- Date: Fri, 4 Apr 2003 17:01:45 +0100
Here is the test case for the reference after free problem.
I compiled the attached program using
gcc -c -g `xml2-config --cflags` xptest.c
gcc xptest.o `xml2-config --libs` -o xptest
running the compiled program gave me the following results :-
The XML file is constructed so that the first two cases produce the same output
$ ./xptest xptest.xml '//token'
<token>12345</token>
<token>abcdefg</token>
<token>67890</token>
<token>zyx</token>
<token>xyzzy</token>
<token>plugh</token>
$ ./xptest xptest.xml 'xp:tokenize(//string)'
<token>12345</token>
<token>abcdefg</token>
<token>67890</token>
<token>zyx</token>
<token>xyzzy</token>
<token>plugh</token>
Next verify the filter gives expected results
$ ./xptest xptest.xml '//token[position() mod 2 = 1]'
<token>12345</token>
<token>67890</token>
<token>xyzzy</token>
confidence check that filter works as expected on the value of a function
returning a node-set
$ ./xptest xptest.xml 'xp:node-set(//token)[position() mod 2 = 1]'
<token>12345</token>
<token>67890</token>
<token>xyzzy</token>
so far so good, the next case should produce the same output as the previous
one.
$ ./xptest xptest.xml 'xp:tokenize(//string)[position() mod 2 = 1]'
xmlEncodeEntitiesReentrant : input not UTF-8
<Ø&6 Ø&6@>
<text>&6@&6@</text>
</Ø&6 Ø&6@>
<À&6 À&6@>
<text>&6@&6 H</text>
</À&6 À&6@>
<Ø&6 Ø&6@>
<text>&6@&6 h</text>
</Ø&6 Ø&6@>
In this case output was corrupt - could just as easily have been a SIGSEGV.
Two possibilities: node persistence should be managed differently than in the
test program. Since this is copied from libexslt, libexslt is buggy as is my
code that is based on that methodology.
Otherwise, libexslt does persistence management as intended and libxml2's
XPath evaluation is buggy as outlined in my original message,
Brian Stafford
<?xml version="1.0"?>
<test xmlns:xp="http://xpath.test/">
<token>12345</token>
<token>abcdefg</token>
<token>67890</token>
<token>zyx</token>
<token>xyzzy</token>
<token>plugh</token>
<string>12345 abcdefg 67890 zyx xyzzy plugh</string>
</test>
#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
static void node_set (xmlXPathParserContextPtr ctxt, int nargs);
static void tokenise (xmlXPathParserContextPtr ctxt, int nargs);
/* usage: ./xpfunctest xml-doc */
int
main (int argc, char **argv)
{
xmlXPathContextPtr ctxt;
xmlXPathObjectPtr obj;
xmlNsPtr ns;
xmlDocPtr doc;
xmlNodePtr node;
xmlChar *string;
int i;
argc--;
argv++;
if (argc < 2)
exit (1);
doc = xmlParseFile (*argv++);
node = xmlDocGetRootElement (doc);
ctxt = xmlXPathNewContext (doc);
ctxt->node = node;
ns = xmlSearchNsByHref (doc, ctxt->node,
(const xmlChar *) "http://xpath.test/");
if (ns != NULL)
xmlXPathRegisterNs (ctxt, ns->prefix, ns->href);
xmlXPathRegisterFuncNS (ctxt,
(const xmlChar *) "node-set",
(const xmlChar *) "http://xpath.test/",
node_set);
xmlXPathRegisterFuncNS (ctxt,
(const xmlChar *) "tokenize",
(const xmlChar *) "http://xpath.test/",
tokenise);
obj = xmlXPathEval ((const xmlChar *) *argv, ctxt);
if (obj != NULL)
{
if (obj->type == XPATH_NODESET || obj->type == XPATH_XSLT_TREE)
{
if (obj->nodesetval != NULL)
for (i = 0; i < obj->nodesetval->nodeNr; i++)
{
xmlElemDump (stdout, doc, obj->nodesetval->nodeTab[i]);
printf ("\n");
}
}
else if ((string = xmlXPathCastToString (obj)) != NULL)
{
printf ("string = '%s'\n", string);
xmlFree (string);
}
xmlXPathFreeObject (obj);
}
exit (0);
}
/* taken from libxslt extra.c */
static void
node_set (xmlXPathParserContextPtr ctxt, int nargs)
{
if (nargs != 1)
{
ctxt->error = XPATH_INVALID_ARITY;
return;
}
if ((ctxt->value == NULL)
|| ((ctxt->value->type != XPATH_XSLT_TREE)
&& (ctxt->value->type != XPATH_NODESET)))
{
ctxt->error = XPATH_INVALID_TYPE;
return;
}
if (ctxt->value->type == XPATH_XSLT_TREE)
{
ctxt->value->type = XPATH_NODESET;
}
}
/* taken from libexslt string.c and modified to avoid reference to xslt
context. */
static void
tokenise (xmlXPathParserContextPtr ctxt, int nargs)
{
xmlChar *str, *delimiters, *cur;
const xmlChar *token, *delimiter;
xmlNodePtr node;
xmlDocPtr doc;
xmlXPathObjectPtr ret;
if ((nargs < 1) || (nargs > 2))
{
xmlXPathSetArityError (ctxt);
return;
}
if (nargs == 2)
{
delimiters = xmlXPathPopString (ctxt);
if (xmlXPathCheckError (ctxt))
return;
}
else
{
delimiters = xmlStrdup ((const xmlChar *) "\t\r\n ");
}
if (delimiters == NULL)
return;
str = xmlXPathPopString (ctxt);
if (xmlXPathCheckError (ctxt) || (str == NULL))
{
xmlFree (delimiters);
return;
}
doc = ctxt->context->doc;
ret = xmlXPathNewNodeSet (NULL);
if (ret != NULL)
{
ret->boolval = 1;
/*
* This is a hack: token elements are added as children of a
* fake element node. This is necessary to free them up
* correctly when freeing the node-set.
*/
ret->user = (void *) xmlNewDocNode (doc, NULL,
(const xmlChar *) "fake", NULL);
if (ret->user == NULL)
goto error;
}
for (cur = str, token = str; *cur != 0; cur++)
{
for (delimiter = delimiters; *delimiter != 0; delimiter++)
{
if (*cur == *delimiter)
{
if (cur == token)
{
/* discard empty tokens */
break;
}
*cur = 0;
node = xmlNewDocNode (doc, NULL,
(const xmlChar *) "token", token);
*cur = *delimiter;
token = cur + 1;
xmlAddChild ((xmlNodePtr) ret->user, node);
xmlXPathNodeSetAdd (ret->nodesetval, node);
break;
}
}
}
node = xmlNewDocNode (doc, NULL, (const xmlChar *) "token", token);
xmlAddChild ((xmlNodePtr) ret->user, node);
xmlXPathNodeSetAdd (ret->nodesetval, node);
valuePush (ctxt, ret);
ret = NULL; /* hack to prevent freeing ret later */
error:
if (ret != NULL)
xmlXPathFreeObject (ret);
if (str != NULL)
xmlFree (str);
if (delimiters != NULL)
xmlFree (delimiters);
}
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]