C++11 libxml++;2.36.“;“双重自由或腐败”;如果引发std::异常

C++11 libxml++;2.36.“;“双重自由或腐败”;如果引发std::异常,c++11,c++14,libxml2,C++11,C++14,Libxml2,Hy, 在为我的代码使用libxml++-2.36库时,我发现当basetype std::exception的异常在sax解析器回调中抛出时,该库会产生“双重释放或损坏”错误。(例如,开始文档、结束文档、打开…) 但是它的行为是正常的,这意味着,如果抛出basetype异常,可以捕获异常 有趣的是,它基于std::exception 为了验证这一点,我创建了一个MWE: #include <libxml++/libxml++.h> #include <iostream>

Hy, 在为我的代码使用libxml++-2.36库时,我发现当basetype std::exception的异常在sax解析器回调中抛出时,该库会产生“双重释放或损坏”错误。(例如,开始文档、结束文档、打开…)

但是它的行为是正常的,这意味着,如果抛出basetype异常,可以捕获异常

有趣的是,它基于std::exception

为了验证这一点,我创建了一个MWE:

#include <libxml++/libxml++.h>
#include <iostream>

class xml_parser : public xmlpp::SaxParser {
protected:
    virtual void on_start_document() override;
};

void xml_parser::on_start_document() {
    throw std::runtime_error("test-exception");
    //throw xmlpp::internal_error("test-exception");
}

int main(void) {
    xml_parser parser;
    try {
        parser.parse_memory(
            u8"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
    } catch (std::exception &e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }
}
如果按原样执行文件,则会得到以下输出:

*** Error in `./main': double free or corruption (!prev): 0x0000000000b35b30 ***
Caught exception: test-exception
如果我取消注释on_start_document()的第二行并注释第一行,我将得到以下输出:

*** Error in `./main': double free or corruption (!prev): 0x0000000000b35b30 ***
Caught exception: test-exception
编译器:g++4.9.2 libxml++:2.6-2.36


有没有一种方法可以让基于std::exception的异常正常工作,而不创建特殊的基于xmlpp::exception的异常?

发生的是一个
\xmlSAXHandler
对象被释放了两次,一次是被
删除的,另一次是被xmlFree()释放的。这可以通过在适当的free()标准libc调用上设置断点来看出。例如,在一台Ubuntu“trusty”计算机上,我在
\u int\u free
上设置了一个断点,发现同一个指针被释放了两次:

Breakpoint 2, _int_free (av=0x7ffff741f760 , p=0x610b80, have_lock=0) at malloc.c:3814 3814 in malloc.c (gdb) bt #0 _int_free (av=0x7ffff741f760 , p=0x610b80, have_lock=0) at malloc.c:3814 #1 0x00007ffff6d32a59 in xmlFreeParserCtxt () from /usr/lib/x86_64-linux-gnu/libxml2.so.2 #2 0x00007ffff7bc6be2 in xmlpp::Parser::release_underlying ( this=this@entry=0x7fffffffdd30) at libxml++/parsers/parser.cc:162 #3 0x00007ffff7bcc665 in xmlpp::SaxParser::release_underlying ( this=this@entry=0x7fffffffdd30) at libxml++/parsers/saxparser.cc:329 #4 0x00007ffff7bcc68c in xmlpp::SaxParser::~SaxParser (this=0x7fffffffdd30, __in_chrg=) at libxml++/parsers/saxparser.cc:83 #5 0x0000000000401d80 in ~xml_parser (this=0x7fffffffdd30, __in_chrg=) at so31969961_libxmlpp_double_free.cpp:7 #6 main () at so31969961_libxmlpp_double_free.cpp:24 ... Breakpoint 2, _int_free (av=0x7ffff741f760 , p=0x610b80, have_lock=0) at malloc.c:3814 3814 in malloc.c (gdb) bt #0 _int_free (av=0x7ffff741f760 , p=0x610b80, have_lock=0) at malloc.c:3814 #1 0x00007ffff7bcc69e in ~auto_ptr (this=0x7fffffffdd60, __in_chrg=) at /usr/include/c++/4.8/backward/auto_ptr.h:170 #2 xmlpp::SaxParser::~SaxParser (this=0x7fffffffdd30, __in_chrg=) at libxml++/parsers/saxparser.cc:81 #3 0x0000000000401d80 in ~xml_parser (this=0x7fffffffdd30, __in_chrg=) at so31969961_libxmlpp_double_free.cpp:7 #4 main () at so31969961_libxmlpp_double_free.cpp:24 断点2,内部空闲(av=0x7ffff741f760,p=0x610b80, 在malloc有_lock=0)。c:3814 malloc.c中的3814 (gdb)英国电信 #0无内部(av=0x7ffff741f760,p=0x610b80,有锁=0) 在malloc.c:3814 #xmlFreeParserCtxt()中的1 0x00007ffff6d32a59 来自/usr/lib/x86_64-linux-gnu/libxml2.so.2 #xmlpp::Parser::release_中的2 0x00007ffff7bc6be2( 这个=this@entry=0x7fffffffdd30),位于libxml++/parsers/parser.cc:162 #xmlpp::SaxParser::release_中的3 0x00007ffff7bc665( 这个=this@entry=0x7fffffffdd30),位于libxml++/parsers/saxparser.cc:329 #xmlpp::SaxParser::~SaxParser中的4 0x00007FFFF7BC68C(此参数=0x7fffffffdd30, __在libxml++/parsers/saxparser.cc:83的_chrg=)中 #~xml_解析器中的5 0x0000000000401d80(此=0x7fffffffdd30, __在so31969961中的in_chrg=)libxmlpp_double_free.cpp:7 #6 main()位于so31969961_libxmlpp_double_free.cpp:24 ... 断点2,内部空闲(av=0x7ffff741f760,p=0x610b80, 在malloc有_lock=0)。c:3814 malloc.c中的3814 (gdb)英国电信 #0无内部(av=0x7ffff741f760,p=0x610b80,有锁=0) 在malloc.c:3814 #自动ptr中的1 0x00007FFFF7BC69E(此=0x7fffffffdd60, __in_chrg=)at/usr/include/c++/4.8/backward/auto_ptr.h:170 #2 xmlpp::SaxParser::~SaxParser(this=0x7fffffffdd30, __在libxml++/parsers/saxparser.cc:81的_chrg=)中 #~xml_解析器中的3 0x0000000000401d80(此=0x7fffffffdd30, __在so31969961中的in_chrg=)libxmlpp_double_free.cpp:7 #4 main()位于so31969961_libxmlpp_double_free.cpp:24 在这种情况下,0x610b80对应于SaxParser在其
sax\u handler\uu
auto\u ptr成员中持有的
\uxmlsaxhandler
对象。它首先由libxml2的xmlFreeParserCtxt()例程释放。然后由
std::auto_ptr
析构函数删除它

如果查看中libxml++的SaxParser类的源代码,您将看到有几个try..catch语句。但是,只捕获了常量异常&
。此
const异常
不是
std::exception
,而是
xmlpp::exception

在on_start_document()处理程序中抛出
std::runtime_错误时,SaxParserCallback::start_document()不会捕获该错误。因此,当堆栈展开时,将跳过SaxParser::parse()中还原
\u xmlSAXHandler
中原始
\u xmlParserCtxt
指针的代码

这样做的好处是,您应该只在SaxParser处理程序方法中抛出从
xmlpp::exception
派生的异常

更新:


UPDATE2:已在版本2.39.2中修复。

谢谢,这意味着您在使用此库时应该非常小心,因为每次调用处理程序中的函数NOTEXCEPT时,您最好先添加一个try catch块。所以我觉得这个图书馆不好用。你会使用这个库吗,现在你知道它是如何工作的了?我应该创建一个BuGePror,还是你认为它不值得。”BytUnn:是的,我会考虑在C++项目中使用需要解析XML的库。毕竟,libxml++是链接到libxml2主页上的。重新创建bug报告:我认为提交bug报告是值得的。目前来看,这一问题似乎尚未报告。