2016-12-08 13 views
0

Ich versuche, eine XML-Datei durch Iterieren über Elemente zu analysieren.Valgrind Speicherverlust in xmlStrndup

Hier ist die grundlegende Methode, die ich aufrufen werde, um das zu tun. Aber ich beobachte ein Leck, wenn diese Methode aufgerufen wird.

Code:

std::string getUrl(std::vector<std::string> keyPath, std::string element, std::string fName) 
{ 

    xmlDocPtr m_doc; 
    xmlNodePtr m_cur; 
    std::string m_fileName; 
    bool isEmpty; 
    int i=0; 
    std::string value = ""; 
    isEmpty = false; 
    m_fileName = fName; 
    struct stat stat_buf; 
    int rc = stat(m_fileName.c_str(), &stat_buf); 
    if(rc==0) 
    { 
     m_doc = xmlParseFile(m_fileName.c_str()); 
    } 
    else 
    { 
     isEmpty = true; 
    } 

    if(isEmpty) 
    { 
     value = "Empty file found"; 
     xmlFreeDoc(m_doc); 
     xmlCleanupCharEncodingHandlers(); 
     xmlCleanupParser(); 
     return value; 
    } 
    if(m_doc != NULL) 
    { 
     m_cur = xmlDocGetRootElement(m_doc); 
    } 
    if(m_cur != NULL) 
    { 
     if(!xmlStrcmp(m_cur->name, (const xmlChar *)(keyPath.at(i).c_str()))) 
     { 
      m_cur = m_cur->xmlChildrenNode; 
      ++i; 
     } 
     else 
     { 
      value = "root element not found"; 
      return value; 
     } 
     while(m_cur != NULL) 
     { 
      if (!xmlStrcmp (m_cur -> name, (const xmlChar *) keyPath.at(i).c_str())) 
      { 
       m_cur = m_cur->xmlChildrenNode; 
       i++; 
      } 
      m_cur = m_cur -> next; 
      if (!xmlStrcmp (m_cur -> name, (const xmlChar *) keyPath.back().c_str())) 
      { 
       m_cur = m_cur->xmlChildrenNode; 
       break; 
      } 
     } 
     while (m_cur != NULL) 
     { 
     if (!xmlStrcmp (m_cur -> name, (const xmlChar *) element.c_str())) 
     { 
      if(xmlNodeGetContent(m_cur->xmlChildrenNode) != NULL) 
      value = (char*)(xmlNodeGetContent(m_cur->xmlChildrenNode)); 
      else 
      value = ""; 
     } 
     m_cur = m_cur -> next; 
     } 
    } 

    //call the necessary cleanup APIs of libxml2 to free the dynamically allocated memory 
    xmlFreeDoc(m_doc); 
    xmlCleanupCharEncodingHandlers(); 
    xmlCleanupParser(); 

    if(!value.empty()) 
    { 
     return value; 
    } 
    else 
    { 
     value = "value not found"; 
     return value; 
    } 
} 

Valgrind Leck ist wie folgt:

==1598== 
==1598== HEAP SUMMARY: 
==1598==  in use at exit: 139,402 bytes in 1,053 blocks 
==1598== total heap usage: 1,222 allocs, 169 frees, 284,997 bytes allocated 
==1598== 
==1598== 28 bytes in 1 blocks are definitely lost in loss record 29 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40198D: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402A56: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 28 bytes in 1 blocks are definitely lost in loss record 30 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x4019A4: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402A56: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 30 bytes in 1 blocks are definitely lost in loss record 31 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40198D: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402CD2: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 30 bytes in 1 blocks are definitely lost in loss record 32 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x4019A4: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402CD2: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 30 bytes in 1 blocks are definitely lost in loss record 33 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40198D: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401FF4: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402F30: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 30 bytes in 1 blocks are definitely lost in loss record 34 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x526D928: xmlStrndup (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x4019A4: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401FF4: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402F30: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 21,852 (176 direct, 21,676 indirect) bytes in 1 blocks are definitely lost in loss record 77 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x5215324: xmlNewDoc (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x52C01B8: xmlSAX2StartDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E25D: xmlParseDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E561: xmlSAXParseFileWithData (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40181A: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402A56: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 21,852 (176 direct, 21,676 indirect) bytes in 1 blocks are definitely lost in loss record 78 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x5215324: xmlNewDoc (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x52C01B8: xmlSAX2StartDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E25D: xmlParseDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E561: xmlSAXParseFileWithData (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40181A: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401BAE: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402CD2: main (in /cluster/home/XmlParser) 
==1598== 
==1598== 21,852 (176 direct, 21,676 indirect) bytes in 1 blocks are definitely lost in loss record 79 of 80 
==1598== at 0x4C2A6FE: malloc (vg_replace_malloc.c:296) 
==1598== by 0x5215324: xmlNewDoc (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x52C01B8: xmlSAX2StartDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E25D: xmlParseDocument (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x520E561: xmlSAXParseFileWithData (in /usr/lib64/libxml2.so.2.9.1) 
==1598== by 0x40181A: getUrl(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x401FF4: parseXmlFile(std::vector<std::string, std::allocator<std::string> >, std::string, std::string) (in /cluster/home/XmlParser) 
==1598== by 0x402F30: main (in /cluster/home/XmlParser) 
==1598== 
==1598== LEAK SUMMARY: 
==1598== definitely lost: 704 bytes in 9 blocks 
==1598== indirectly lost: 65,028 bytes in 1,023 blocks 
==1598==  possibly lost: 0 bytes in 0 blocks 
==1598== still reachable: 73,670 bytes in 21 blocks 
==1598==   suppressed: 0 bytes in 0 blocks 
==1598== Reachable blocks (those to which a pointer was found) are not shown. 
==1598== To see them, rerun with: --leak-check=full --show-leak-kinds=all 
==1598== 
==1598== For counts of detected and suppressed errors, rerun with: -v 
==1598== ERROR SUMMARY: 9 errors from 9 contexts (suppressed: 0 from 0) 

ich es wirklich schätzen würde, wenn Sie mir die Sache helfen könnten, die tatsächlich das Leck verursacht. Vielen Dank im Voraus

+0

Versuchen Sie das Kompilieren ohne Optimierung und aktivieren Sie das vollständige Debugging. Dann wird Valgrind Ihnen sagen, wo das Problem genau ist. – Jonas

+0

Wenn ich es normal kompiliert habe, ist oben die Valgrind-Ausgabe, die ich bekommen habe. Immer noch nicht sicher, was das Problem ist – AbhinayB

Antwort

1

Dieses Stück Code bewirkt, dass die beiden Speicherlecks:

if(xmlNodeGetContent(m_cur->xmlChildrenNode) != NULL) 
    value = (char*)(xmlNodeGetContent(m_cur->xmlChildrenNode)); 
else 
    value = ""; 

xmlNodeGetContent gibt eine Zeichenfolge, die mit xmlFree befreit werden müssen. So sollte der Code wie folgt aussehen:

xmlChar *content = xmlNodeGetContent(m_cur->xmlChildrenNode); 
if (content != NULL) { 
    value = (char*)content; 
    xmlFree(content); 
} 
else { 
    value = ""; 
} 

Sie manchmal auch die xmlDoc auslaufen. Dies kann durch den Rückpfad "root element not found" verursacht werden, der das Dokument nicht freigibt.

0

Nun hat nwellnhof Ihnen die Antwort auf Ihre Fragen gegeben, wo die Lecks sind.

Ich werde versuchen, Ihnen zu sagen, wie Sie sie beheben. Beachte ungeprüften Code.

Wir sind hier (falsch) mit std::unique_ptr als scope_guard.

Zuerst machen Sie eine Generel get String-Methode, die das String-freie Problem behebt.

std::string xmlGetString(xmlNodePtr m_cur) { 
    std::unique_ptr<xmlChar> 
    content(xmlNodeGetContent(m_cur->xmlChildrenNode), xmlFree); // 1 

    if (content != NULL) { 
    return (char*)content; 
    } else { 
    return ""; 
    } 
} 

Anmerkung 1: xmlFree ist der deleter in std::unique_ptr

wenn xmlFree NULL findet nicht auf eine Antwort, dass in einer anderen Methode packen musst, die vor dem Aufruf xmlFree für NULL überprüft.

(Dies sieht grob ineffizient, xmlNodeGetContent macht eine Kopie von einigen internen Daten, die dann als std::string, eine weitere Kopie des Textes, mindestens die endgültige Kopie der Zeichenfolge in den lvalue im Aufrufer erforderlich sein kann elided.)

gleichen Trick mit xmlFreeDoc, zuerst ein wenig Rewrite

if (rc != 0) { 
    // any other xml clean up needed??? 
    return "Empty file found"; 
} 

dann danach erklären ihn als

std::unique_ptr<xmlDoc> m_doc(xmlParseFile(m_fileName.c_str()), Cleanup); 
// note the ptr is gone to the unique_ptr 

und eine zusätzliche Methode

void Cleanup(xmlDocPtr m_doc) { 
    xmlFreeDoc(m_doc); 
    xmlCleanupCharEncodingHandlers(); 
    xmlCleanupParser(); 
} 

Dann, wenn m_doc den Umfang verlässt Cleanup genannt wird.

Jetzt müssen Sie Ihre Aufräumarbeiten aufräumen, damit Sie nicht unnötig arbeiten.

Sie sollten entweder alle anderen XML-Funktionen in einige C++ packen oder Ihre XML-Bibliothek ändern.

Verwandte Themen