为什么valgrind在这个mini-xml代码中报告泄漏?

时间:2015-05-04 21:27:00

标签: c xml parsing memory-leaks valgrind

我在linux系统上使用c和mini-xml(http://www.msweet.org/projects.php?Z3)解析一些简单的XML:

<?xml version="1.0" encoding="utf-8" ?>
<quran type="metadata" version="1.0" copyright="(C) 2008-2009 Tanzil.info" license="cc-by">
    <suras alias="chapters">
        <sura index="1" ayas="7" start="0" name="الفاتحة" tname="Al-Faatiha" ename="The Opening" type="Meccan" order="5" rukus="1" />
        <sura index="2" ayas="286" start="7" name="البقرة" tname="Al-Baqara" ename="The Cow" type="Medinan" order="87" rukus="40" />
...

我在这段代码中得到了valgrind泄漏报告:

FILE* xmlMetaFile = fopen("/home/muhammad/Development/HifzHelper/dbgen/quran-metadata.xml", "r");
mxml_node_t *xmlDocument = mxmlLoadFile(NULL, xmlMetaFile, MXML_IGNORE_CALLBACK);
for (mxml_node_t* xmlNode = mxmlFindElement(xmlDocument, xmlDocument, "sura", NULL, NULL, MXML_DESCEND); xmlNode != NULL; xmlNode = mxmlFindElement(xmlNode, xmlDocument, "sura", NULL, NULL, MXML_DESCEND))
{
    ...
}

特此在这一行:

mxml_node_t *xmlDocument = mxmlLoadFile(NULL, xmlMetaFile, MXML_IGNORE_CALLBACK);

这很奇怪,因为文档(http://www.msweet.org/documentation/project3/Mini-XML.html#3_4)指示这样编写它。

Valgrind输出:

==4045== Memcheck, a memory error detector
==4045== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4045== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4045== Command: ./dbgen
==4045== 
==4045== 
==4045== HEAP SUMMARY:
==4045==     in use at exit: 281,994 bytes in 15,534 blocks
==4045==   total heap usage: 244,265 allocs, 228,731 frees, 60,275,346 bytes allocated
==4045== 
==4045== 281,994 (88 direct, 281,906 indirect) bytes in 1 blocks are definitely lost in loss record 9 of 9
==4045==    at 0x4C2C934: calloc (vg_replace_malloc.c:623)
==4045==    by 0x50F6300: mxml_new (mxml-node.c:751)
==4045==    by 0x50F63A7: mxmlNewElement (mxml-node.c:400)
==4045==    by 0x50F4742: mxml_load_data (mxml-file.c:1953)
==4045==    by 0x400E52: main (dbgen.c:57)
==4045== 
==4045== LEAK SUMMARY:
==4045==    definitely lost: 88 bytes in 1 blocks
==4045==    indirectly lost: 281,906 bytes in 15,533 blocks
==4045==      possibly lost: 0 bytes in 0 blocks
==4045==    still reachable: 0 bytes in 0 blocks
==4045==         suppressed: 0 bytes in 0 blocks
==4045== 
==4045== For counts of detected and suppressed errors, rerun with: -v
==4045== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)

Done.

这是我的程序或mini-xml中的错误吗?

编辑(完整代码):

#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>
#include <mxml.h>

int main(int argc, char *argv[])
{
    // open connection
    sqlite3 *conn;
    sqlite3_initialize();
    sqlite3_open_v2("hifzhelper.sl3", &conn, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);

    // create ayaat table
    sqlite3_exec(conn, "CREATE TABLE Ayaat (Id INTEGER PRIMARY KEY, SurahNo INTEGER, AyahNo INTEGER, AyahText TEXT, Status INTEGER DEFAULT 0)", NULL, NULL, NULL);
    sqlite3_exec(conn, "BEGIN TRANSACTION;", NULL, NULL, NULL);

    // open ayaat data file
    FILE* ayaatFile = fopen("/home/muhammad/Development/HifzHelper/dbgen/quran.txt", "r");
    if(ayaatFile == NULL)
    {
        puts("quran file not found");
        return 1;
    }

    char sql[2048];
    char line[2048];

    while(fgets(line, 2048, ayaatFile))
    {
        char* parts[3];
        parts[0] = strtok(line, "|");
        for(int i = 1; i < 3; i++)
        {
            parts[i] = strtok (NULL, "|");
        }   

        int ayahNo = atoi(parts[0]);
        int surahNo = atoi(parts[1]);
        char *ayahText = parts[2];
        int status = 0;

        sprintf(sql, "INSERT INTO Ayaat (SurahNo, AyahNo, AyahText, Status) VALUES (%d, %d, '%s', %d)", surahNo, ayahNo, ayahText, status);
        sqlite3_exec(conn, sql, NULL, NULL, NULL);
    }

    // ayaat index
    sqlite3_exec(conn, "CREATE INDEX IDX_SurahAyah ON Ayaat (SurahNo, AyahNo);", NULL, NULL, NULL);
    sqlite3_exec(conn, "END TRANSACTION;", NULL, NULL, NULL);

    // create surahs table
    sqlite3_exec(conn, "CREATE TABLE Surahs (Id INTEGER PRIMARY KEY, Name TEXT, AyahCount INTEGER)", NULL, NULL, NULL); 

    // extract surahs 
    sqlite3_exec(conn, "BEGIN TRANSACTION;", NULL, NULL, NULL);  
    FILE* xmlMetaFile = fopen("/home/muhammad/Development/HifzHelper/dbgen/quran-metadata.xml", "r");
    mxml_node_t *xmlDocument = mxmlLoadFile(NULL, xmlMetaFile, MXML_IGNORE_CALLBACK);
    for (mxml_node_t* xmlNode = mxmlFindElement(xmlDocument, xmlDocument, "sura", NULL, NULL, MXML_DESCEND); xmlNode != NULL; xmlNode = mxmlFindElement(xmlNode, xmlDocument, "sura", NULL, NULL, MXML_DESCEND))
    {
        int surahNo = atoi(mxmlElementGetAttr(xmlNode, "index"));
        const char* surahName = mxmlElementGetAttr(xmlNode, "name");
        int ayahCount = atoi(mxmlElementGetAttr(xmlNode, "ayas"));

        sprintf(sql, "INSERT INTO Surahs (Id, Name, AyahCount) VALUES (%d, '%s', %d)", surahNo, surahName, ayahCount);
        sqlite3_exec(conn, sql, NULL, NULL, NULL);
    }
    sqlite3_exec(conn, "END TRANSACTION;", NULL, NULL, NULL);

    // create reminder tables
    sqlite3_exec(conn, "CREATE TABLE Reminders (Id INTEGER PRIMARY KEY AUTOINCREMENT, StartAyah INTEGER, EndAyah INTEGER, TimeFactor INTEGER DEFAULT 0, Due DATETIME, Status INTEGER DEFAULT 0)", NULL, NULL, NULL);

    // vaccuum
    sqlite3_exec(conn, "VACUUM;", NULL, NULL, NULL);

    // cleanup
    fclose(ayaatFile);
    fclose(xmlMetaFile);

    if (NULL != conn)
        sqlite3_close(conn);

    sqlite3_shutdown();
    return 0;
}

2 个答案:

答案 0 :(得分:1)

解决方案是:

mxmlDelete(xmlDocument); // release mem

释放XML树占用的内存。它在文档中进一步提到,我没有阅读该部分。

答案 1 :(得分:-1)

成功加载文件后(代码未检查) 然后在处理文件之后,仍然有指针(mxml_node_t *xmlDocument),它是指向已分配内存的指针。

指针应该通过以下方式传递给free:free(xmlDocument);