在libxml2的xmlCopyNodeList中发生内存泄漏

时间:2014-05-29 14:31:31

标签: c++ c memory-leaks libxml2

我在使用libxml2时遇到了问题。

我正在尝试复制节点列表并将其保存到文件中。代码构建并运行但是当我在valgrind中运行它时会出现错误。

这是我的测试代码:test_libxml.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

#define RSS_XML           "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"\
                          "<rss version=\"2.0\">\n"\
                          "\t<channel>\n"\
                          "\t\t<item>\n"\
                          "\t\t\t<title>Some Title</title>\n"\
                          "\t\t\t<description>Some Description</description>\n"\
                          "\t\t</item>\n\t\t<item>\n"\
                          "\t\t\t<title>Another Title</title>\n"\
                          "\t\t\t<description>Another Description</description>\n"\
                          "\t\t</item>\n"\
                          "\t</channel>\n"\
                          "</rss>\n"


static const char document [] = RSS_XML;

static int  parse_rss (const char *content, int content_len);
static void parse_channel (xmlNodePtr channel);
static void save_item (xmlNodePtr item);

int main (int argc, char *argv[])
{
    int ret = 1;

    xmlInitParser ();

    ret = parse_rss (document, sizeof (document) - 1);

    xmlCleanupParser();
    xmlMemoryDump();

    return ret;
}

static int parse_rss (const char *content, int content_len)
{
    xmlParserCtxtPtr parser;
    xmlDocPtr doc;

    parser = xmlNewParserCtxt ();
    if (parser == NULL) {
        fprintf (stderr, "Failed to creste parser\n");
        return 1;
    }


    doc = xmlCtxtReadMemory (parser, content, content_len, NULL, NULL, 0);
    if (doc == NULL) {
        xmlFreeParserCtxt (parser);
        fprintf (stderr, "Failed to parse document\n");
        return 1;
    }


    xmlNodePtr root = xmlDocGetRootElement (doc);
    xmlNodePtr node = root->children;

    while (node) {
        if (node->type == XML_ELEMENT_NODE
            && xmlStrEqual (node->name, BAD_CAST "channel"))
        {
            parse_channel (node);
        }

        node = node->next;
    }

    xmlFreeDoc (doc);
    xmlFreeParserCtxt (parser);

    return 0;
} 

static void parse_channel (xmlNodePtr channel)
{
    xmlNodePtr node = channel->children;

    while (node) {
        if (node->type == XML_ELEMENT_NODE
            && xmlStrEqual (node->name, BAD_CAST "item"))
        {
            save_item (node);
        }

        node = node->next;
    }
}

static void save_item (xmlNodePtr item)
{
    static int i = 0;
    char filename [200];

    sprintf (filename, "item_%d.xml", i++);

    xmlDocPtr doc = xmlNewDoc (NULL);
    if (doc == NULL) {
        return;
    }

    xmlNodePtr temp = xmlCopyNodeList (item);
    if (temp == NULL) {
        xmlFreeDoc (doc);
        return;
    }

    xmlDocSetRootElement (doc, temp);

    xmlSaveFile (filename, doc);

    xmlUnlinkNode (temp);
    xmlFreeNodeList (temp);
    xmlFreeDoc (doc);
}

这是valgrind输出:

==6581== Memcheck, a memory error detector
==6581== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6581== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==6581== Command: ./build/test_libxml
==6581== 
==6581== 
==6581== HEAP SUMMARY:
==6581==     in use at exit: 741 bytes in 22 blocks
==6581==   total heap usage: 145 allocs, 123 frees, 26,427 bytes allocated
==6581== 
==6581== 741 (120 direct, 621 indirect) bytes in 2 blocks are definitely lost in loss record 9 of 9
==6581==    at 0x4006ADD: malloc (vg_replace_malloc.c:291)
==6581==    by 0x8076696: xmlStaticCopyNode (in test_libxml)
==6581==    by 0x8076B70: xmlStaticCopyNodeList (in test_libxml)
==6581==    by 0x8076C71: xmlCopyNodeList (in test_libxml)
==6581==    by 0x8049925: save_item (test_libxml.c:107)
==6581==    by 0x80498C2: parse_channel (test_libxml.c:88)
==6581==    by 0x804984F: parse_rss (test_libxml.c:68)
==6581==    by 0x8049734: main (test_libxml.c:33)
==6581== 
==6581== LEAK SUMMARY:
==6581==    definitely lost: 120 bytes in 2 blocks
==6581==    indirectly lost: 621 bytes in 20 blocks
==6581==      possibly lost: 0 bytes in 0 blocks
==6581==    still reachable: 0 bytes in 0 blocks
==6581==         suppressed: 0 bytes in 0 blocks
==6581== 
==6581== For counts of detected and suppressed errors, rerun with: -v
==6581== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 8)

libxml2版本是2.9.1

感谢任何帮助。谢谢

1 个答案:

答案 0 :(得分:0)

正如@nwellnhof所说

正确使用的函数确实是xmlCopyNode。

这是正确的代码

static void save_item (xmlNodePtr item)
{
    static int i = 0;
    char filename [200];

    sprintf (filename, "item_%d.xml", i++);

    xmlDocPtr doc = xmlNewDoc (NULL);
    if (doc == NULL) {
        return;
    }

    xmlNodePtr temp = xmlCopyNode(item, 1);
    if (temp == NULL) {
        xmlFreeDoc (doc);
        return;
    }

    xmlDocSetRootElement (doc, temp);

    xmlSaveFile (filename, doc);

    xmlFreeDoc (doc);
}