当来自 xmlDoc 的 xmlFreeNode 和 xmlNewChild 时,libxml2 发生内存泄漏

问题描述 投票:0回答:1

我正在构建一个程序,使用 libxml2 v2.13 在两个 xml 文件之间进行合并验证。

总而言之,在尝试验证 DOM 之间的一些合并(使用 libxml2 的模式和模式功能)时,我注意到当取消链接然后删除子节点时,如果然后我尝试添加新的子节点,我会收到内存泄漏和错误的报告瓦尔格林德。

我已经用这个示例程序重现了这个问题:

/**
 * section: Parsing
 * synopsis: Parse an XML document in memory to a tree and free it
 * purpose: Demonstrate the use of xmlReadMemory() to read an XML file
 *          into a tree and xmlFreeDoc() to free the resulting tree
 * usage: parse3
 * test: parse3
 * author: Daniel Veillard
 * copy: see Copyright for the status of this software.
 */

#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
static const char *document = "<doc/>";
static xmlNodePtr findNode( xmlNodePtr sibling ,char * node_name){
    xmlNodePtr next_sibling = sibling;
    while(next_sibling){
        if(strncmp((char*)next_sibling->name, node_name,  strlen(node_name))){
            break;
        }

    }
    return next_sibling;

}
/**
 * example3Func:
 * @content: the content of the document
 * @length: the length in bytes
 *
 * Parse the in memory document and free the resulting tree
 */
static void
example3Func(const char *content, int length) {
    xmlDocPtr doc; /* the resulting document tree */

    /*
     * The document being in memory, it have no base per RFC 2396,
     * and the "noname.xml" argument will serve as its base.
     */
    doc = xmlReadMemory(content, length, "customization.xml", NULL, 0);
    if (doc == NULL) {
        fprintf(stderr, "Failed to parse document\n");
    return;
    }else{
        fprintf(stdout, "DOM loaded\n");
    }
    xmlNodePtr rec_node = findNode(doc->children,"recording_configurations");
    if(rec_node){
        fprintf(stdout, "Found rec_node\n");
        xmlNodePtr config_node = findNode(rec_node,"configuration_1");
        xmlUnlinkNode(config_node);
        xmlReconciliateNs(doc, rec_node);
        xmlFreeNode(config_node);
        config_node = xmlNewChild(rec_node, NULL, (xmlChar*)"configuration_2",NULL);
        printf("%s\n",rec_node->children->name);
    }

    xmlFreeDoc(doc);
}

int main(void) {
    /*
     * this initialize the library and check potential ABI mismatches
     * between the version it was compiled for and the actual shared
     * library used.
     */

    example3Func(document, 6);

    /*
     * Cleanup function for the XML library.
     */
    xmlCleanupParser();
    /*
     * this is to debug memory for regression tests
     */
    xmlMemoryDump();
    return(0);
}

而 valgrind 的输出将是:

jlm@esswlab3:~/projects/xmlTests/parser$ make
cc -MM -Wall -O2  -I/usr/include/libxml2 parser.c > parser.dep
cc -Wall -O2  -I/usr/include/libxml2 -o parser.o -c parser.c
cc -o parser parser.o -lm -lz -lsystemd -lxml2
jlm@esswlab3:~/projects/xmlTests/parser$ valgrind ./parser
==310107== Memcheck, a memory error detector
==310107== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==310107== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==310107== Command: ./parser
==310107==
DOM loaded
Found rec_node
==310107== Invalid read of size 4
==310107==    at 0x48DC617: xmlNewChild (tree.c:2913)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d332f8 is 8 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid read of size 8
==310107==    at 0x48DC680: xmlNewChild (tree.c:2915)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33330 is 64 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid read of size 8
==310107==    at 0x48DC689: xmlNewChild (tree.c:2915)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33338 is 72 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid read of size 8
==310107==    at 0x48DC639: xmlNewChild (tree.c:2936)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33330 is 64 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid read of size 8
==310107==    at 0x48DC63D: xmlNewChild (tree.c:2937)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33308 is 24 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid write of size 8
==310107==    at 0x48DC698: xmlNewChild (tree.c:2938)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33308 is 24 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid write of size 8
==310107==    at 0x48DC69C: xmlNewChild (tree.c:2939)
==310107==    by 0x109282: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33310 is 32 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
==310107== Invalid read of size 8
==310107==    at 0x109283: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Address 0x4d33308 is 24 bytes inside a block of size 120 free'd
==310107==    at 0x484B27F: free (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x10926F: main (in /home/jlm/projects/xmlTests/parser)
==310107==  Block was alloc'd at
==310107==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==310107==    by 0x48D78C4: xmlNewNodeEatName (tree.c:2247)
==310107==    by 0x48DC6D2: xmlNewDocNodeEatName (tree.c:2319)
==310107==    by 0x48D326B: xmlSAX2StartElementNs (SAX2.c:2101)
==310107==    by 0x48BFCA2: xmlParseStartTag2 (parser.c:9497)
==310107==    by 0x48C265F: xmlParseElementStart (parser.c:9893)
==310107==    by 0x48C43DC: xmlParseElement (parser.c:9828)
==310107==    by 0x48C99E7: xmlParseDocument (parser.c:10618)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13728)
==310107==    by 0x48CD251: xmlCtxtParseDocument (parser.c:13712)
==310107==    by 0x48CD670: xmlReadMemory (parser.c:13855)
==310107==    by 0x1091E4: main (in /home/jlm/projects/xmlTests/parser)
==310107==
configuration_2
==310107==
==310107== HEAP SUMMARY:
==310107==     in use at exit: 120 bytes in 1 blocks
==310107==   total heap usage: 27 allocs, 26 frees, 12,862 bytes allocated
==310107==
==310107== LEAK SUMMARY:
==310107==    definitely lost: 120 bytes in 1 blocks
==310107==    indirectly lost: 0 bytes in 0 blocks
==310107==      possibly lost: 0 bytes in 0 blocks
==310107==    still reachable: 0 bytes in 0 blocks
==310107==         suppressed: 0 bytes in 0 blocks
==310107== Rerun with --leak-check=full to see details of leaked memory
==310107==
==310107== For lists of detected and suppressed errors, rerun with: -s
==310107== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

注意,我已经编译了 libxml2 源代码,以便从 valgrind 获取 libxml2 中的详细跟踪信息。

我是否缺少与 DOM 或命名空间的任何类型的取消链接?我的工作流程正确吗?有人知道这里的问题是什么吗?

提前致谢。

c valgrind libxml2
1个回答
0
投票

我认为

findNode
函数中的错误是由
if
语句中的错误条件引起的。
strncmp
函数用于将节点名称与提供的
node_name
字符串进行比较。然而,
if
语句中的条件是检查字符串是否不相等,而不是检查它们是否相等。

所以这一行:

if(strncmp((char*)next_sibling->name, node_name,  strlen(node_name))){

必须更改为:

if (!strncmp((char*)next_sibling->name, node_name, strlen(node_name)))

© www.soinside.com 2019 - 2024. All rights reserved.