簡體   English   中英

xmlStrndup中的Valgrind內存泄漏

[英]Valgrind memory leak in xmlStrndup

我試圖通過遍歷元素來解析xml文件。

這是我將要調用的基本方法。 但是,每當調用此方法時,我都會觀察到泄漏。

碼:

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泄漏如下:

==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)

如果您能幫助我真正造成泄漏的事情,我將不勝感激。 提前致謝

這段代碼導致了兩次內存泄漏:

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

xmlNodeGetContent返回必須使用xmlFree釋放的字符串。 因此,代碼應如下所示:

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

您有時還會泄漏xmlDoc 這可能是由於無法釋放文檔的“找不到根元素”返回路徑引起的。

現在,nwellnhof已為您解答了泄漏點所在的問題。

我會盡力告訴您如何修復它們。 注意未經測試的代碼。

我們在這里(st-)使用std::unique_ptr作為scope_guard。

首先創建一個通用的獲取字符串方法,該方法可以解決無字符串問題。

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 "";
  }
}

注意1:xmlFree是std::unique_ptr的刪除器

如果xmlFree的答案不為NULL,則必須在調用xmlFree之前將其打包到另一個檢查NULL的方法中。

(這看起來效率很低,xmlNodeGetContent復制了一些內部數據,然后以std::string返回,需要文本的另一個副本,至少可以省略字符串到調用方中左值的最終副本。 )

xmlFreeDoc相同的技巧,首先進行一些重寫

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

然后將其聲明為

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

和其他方法

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

然后,當m_doc離開范圍時,將調用Cleanup

現在您需要清理,以免做不必要的工作。

您應該將所有其他xml函數打包到某些c ++中,或者更改xml庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM