[Libguestfs] [PATCH v2] v2v: Free XML objects in the correct order.
Pino Toscano
ptoscano at redhat.com
Mon Jun 29 16:43:14 UTC 2015
In data giovedì 25 giugno 2015 21:35:41, Richard W.M. Jones ha scritto:
> If you free an xmlDocPtr before any xmlXPathObjectPtrs that reference
> the doc, you'll get valgrind errors like this:
>
> ==7390== Invalid read of size 4
> ==7390== at 0x4EB8BC6: xmlXPathFreeNodeSet (xpath.c:4185)
> ==7390== by 0x4EB8CC5: xmlXPathFreeObject (xpath.c:5492)
> ==7390== by 0x400A56: main (in /tmp/test)
> ==7390== Address 0x60c0928 is 8 bytes inside a block of size 120 free'd
> ==7390== at 0x4C29D2A: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==7390== by 0x4E8784F: xmlFreeNodeList (tree.c:3683)
> ==7390== by 0x4E87605: xmlFreeDoc (tree.c:1242)
> ==7390== by 0x400A4A: main (in /tmp/test)
>
> The following simple test program demonstrates the problem:
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <assert.h>
> #include <libxml/xpath.h>
>
> int
> main (int argc, char *argv[])
> {
> xmlDocPtr doc;
> xmlXPathContextPtr xpathctx;
> xmlXPathObjectPtr xpathobj;
>
> doc = xmlReadMemory ("<test/>", 7, NULL, NULL, XML_PARSE_NONET);
> assert (doc);
> xpathctx = xmlXPathNewContext (doc);
> assert (xpathctx);
> xpathobj = xmlXPathEvalExpression (BAD_CAST "/test", xpathctx);
> assert (xpathobj);
> xmlFreeDoc (doc);
> xmlXPathFreeObject (xpathobj);
> xmlXPathFreeContext (xpathctx);
> exit (EXIT_SUCCESS);
> }
>
> In virt-v2v we were not freeing up objects in the correct order,
> because we didn't express the dependency between objects at the C
> level into the OCaml, where the OCaml garbage collector could see
> those dependencies. For example code like:
>
> let doc = ... in
> let xpathctx = xpath_new_context doc in
> let xpathobj = xpath_eval_expression xpathctx "/foo" in
>
> might end up freeing the 'doc' (xmlDocPtr) if, say, there were no
> further references to it in the code, even though the 'xpathobj'
> (xmlXPathObjectPtr) remains live.
>
> To avoid this, we change the OCaml-level representation of objects
> like xpathobj so they contain a reference back to the higher-level
> objects (xpathctx & doc). Therefore holding an xpathobj means that
> the doc cannot be freed.
>
> However that alone is not quite sufficient. There is a further
> problem when the program calls Gc.full_major, Gc.compact etc., or even
> just when xpathctx & doc happen to be freed at the same time. The GC
> won't necessarily free them in the right order as it knows both need
> to be freed but doesn't know that one must be freed before the other.
>
> To solve this we have to move the finalisers into OCaml code, since
> the OCaml Gc.finalise function comes with an explicit ordering
> guarantee (that finalisers are always called in reverse order that
> they were created), which the C-level finaliser does not.
> ---
> [...]
A bit convoluted, but seems needed if there's no way to do the same at
the C-interface level (maybe manually doing reference counting of
objects, but would seem even more convoluted...)
LGTM.
Thanks,
--
Pino Toscano
More information about the Libguestfs
mailing list