HY, 当我的代码使用libxml ++ - 2.36-library时,我发现,当在sax-parser-callbacks中抛出basetype std :: exception的异常时,这个库会产生“双重释放或损坏”错误。 (例如on_start_document,on_end_document,on _...)
但它表现正常,这意味着,如果抛出了基类型xmlpp::exception的异常,则可以捕获异常。
有趣的是xmlpp::exception基于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;
}
}
可以通过以下方式编译:
g++ main.cpp -o main `pkg-config --cflags --libs libxml++-2.6` -Wall -pedantic -Wextra -Werror -Wcast-qual -Wcast-align -Wconversion -fdiagnostics-color=auto -g -O2 -std=c++11
如果按原样执行文件,我会得到以下输出:
*** Error in `./main': double free or corruption (!prev): 0x0000000000b35b30 ***
如果我取消注释第二行并注释on_start_document()的第一行,我会得到以下输出:
Caught exception: test-exception
编译器:g ++ 4.9.2 libxml ++:2.6 - 2.36
有没有办法让std :: exception的异常工作,而不创建特殊的xmlpp ::基于异常的异常?
答案 0 :(得分:1)
正在发生的事情是_xmlSAXHandler
对象被释放两次,一次由delete
释放,另一次由xmlFree()释放。通过在适当的free()标准libc调用上设置断点可以看出这一点。例如,在Ubuntu&#39; trusty&#39;机器,我在_int_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
在这种情况下,0x610b80对应于SaxParser在其_xmlSAXHandler
auto_ptr成员中持有的sax_handler_
对象。它首先由libxml2的xmlFreeParserCtxt()例程释放。然后由std::auto_ptr<_xmlSAXHandler>
析构函数删除它。
如果你看一下libxml ++的SaxParser类的来源,在saxparser.cc
中,你会看到有几个try..catch语句。但是,只有const exception&
被捕获。此const exception
不是std::exception
,而是xmlpp::exception
。
当您在on_start_document()处理程序中抛出std::runtime_error
时,它不会被SaxParserCallback :: start_document()捕获。因此,当堆栈展开时,将跳过恢复_xmlSAXHandler
中原始_xmlParserCtxt
指针的SaxParser :: parse()中的代码。
这样做的一点是,你应该只在SaxParser处理程序方法中抛出源自xmlpp::exception
的异常。
更新: https://bugzilla.gnome.org/show_bug.cgi?id=753570
UPDATE2:已在2.39.2版中修复。