使用 -O1 优化标志编译项目时共享库崩溃
Shared library crash when project compiled with -O1 optimization flag
问题:
我正在将新的共享库连接到项目。它加载了 运行 次动态链接。
这个新的共享库正在调用另一个共享库。
如果项目使用 -O0
标志编译 - 一切正常。
如果项目是用 -O1
标志编译的 - 这个新库调用的库将得到
Invalid free() / delete / delete[] / realloc()
崩溃总是与 std::string
、basic_string
或 std::basic_stringbuf
相关联。
检查了什么:
Valgrind 在崩溃前没有显示任何应用程序问题。
我尝试过:
- 将库从 运行 时动态链接更改为加载时动态链接
- 检查 lib 是否使用与我相同的 gcc 编译 (
4.4.7
) - 似乎是这样,至少 grep 在 .so 文件中找到了 GCC 4.4.7。
回溯
来自 Valgrind 运行:核心转储堆栈具有各种底部部分,但上部通常如下所示:
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0xF5BE9A6: std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5C2AB4: std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5A8C7F: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5A8E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5BC43D: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib64/libstdc++.so.6.0.13)
.......
==46601== Address 0xf81a2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE"
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0xF5C4564: std::string::assign(std::string const&) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0x21632E52: operator= (basic_string.h:511)
==46601== by 0x21632E52: str (sstream:129)
==46601== by 0x21632E52: str (sstream:557)
.........
==46601== Address 0xf81a2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE"
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0x2308A103: _M_dispose (basic_string.h:236)
==46601== by 0x2308A103: ~basic_string (basic_string.h:503)
.......
==46601== Address 0x67b2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE@@GLIBCXX_3.4"
编辑:
D_GLIBCXX_FULLY_DYNAMIC_STRING
宏有点帮助。
现在
my project -O1
: so.file -O0
有效
my project -O1
: so.file -O1
失败
问题
我没有这些库的代码。
我想知道我还能做些什么来解决这个问题。
调查的下一步应该是什么?
What should be next steps in investigation?
你应该开始调试了。通常 -O0
的错误 "get away it" 只会在优化稍微启动时受到严重打击。
因为我不知道你的代码我只能猜测。
我假设您创建了某种仅供您的共享库使用的对象。可能是某种样板。你将它传递给你的共享库,它会对其进行一些处理,然后将其删除。
因为您从未在自己的代码中读取此变量,所以编译器很有可能将其优化掉。
要解决您的问题,您必须找到该特定变量并将其标记为 volatile
以防止它被优化掉。
祝你好运。
$ c++filt _ZNSs4_Rep20_S_empty_rep_storageE
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_S_empty_rep_storage
_S_empty_rep_storage
声明为:
// The following storage is init'd to 0 by the linker, resulting
// (carefully) in an empty string with one reference.
static size_type _S_empty_rep_storage[];
并定义为:
// Linker sets _S_empty_rep_storage to all 0s (one reference, empty string)
// at static init time (before static ctors are run).
template<typename _CharT, typename _Traits, typename _Alloc>
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::_Rep::_S_empty_rep_storage[
(sizeof(_Rep_base) + sizeof(_CharT) + sizeof(size_type) - 1) /
sizeof(size_type)];
您加载的共享库似乎有另一个(较旧的)_S_empty_rep_storage
定义。在旧版本的 GNU C++ 库中,_S_empty_rep_storage
曾经是动态分配的,这就是共享库尝试执行 delete _S_empty_rep_storage
并崩溃的原因。
解决方法是使用相同的 C++ 编译器和链接器选项针对您使用的 C++ 库重新编译共享库。
我得到了 3-rd pt 库源,结果发现它也执行 dlopen 并出现以下错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42679
问题:
我正在将新的共享库连接到项目。它加载了 运行 次动态链接。
这个新的共享库正在调用另一个共享库。
如果项目使用 -O0
标志编译 - 一切正常。
如果项目是用 -O1
标志编译的 - 这个新库调用的库将得到
Invalid free() / delete / delete[] / realloc()
崩溃总是与 std::string
、basic_string
或 std::basic_stringbuf
相关联。
检查了什么:
Valgrind 在崩溃前没有显示任何应用程序问题。
我尝试过:
- 将库从 运行 时动态链接更改为加载时动态链接
- 检查 lib 是否使用与我相同的 gcc 编译 (
4.4.7
) - 似乎是这样,至少 grep 在 .so 文件中找到了 GCC 4.4.7。
回溯
来自 Valgrind 运行:核心转储堆栈具有各种底部部分,但上部通常如下所示:
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0xF5BE9A6: std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5C2AB4: std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5A8C7F: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5A8E25: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0xF5BC43D: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib64/libstdc++.so.6.0.13)
.......
==46601== Address 0xf81a2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE"
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0xF5C4564: std::string::assign(std::string const&) (in /usr/lib64/libstdc++.so.6.0.13)
==46601== by 0x21632E52: operator= (basic_string.h:511)
==46601== by 0x21632E52: str (sstream:129)
==46601== by 0x21632E52: str (sstream:557)
.........
==46601== Address 0xf81a2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE"
==46601== Invalid free() / delete / delete[] / realloc()
==46601== at 0x4C287CA: operator delete(void*) (vg_replace_malloc.c:507)
==46601== by 0x2308A103: _M_dispose (basic_string.h:236)
==46601== by 0x2308A103: ~basic_string (basic_string.h:503)
.......
==46601== Address 0x67b2c0 is 0 bytes inside data symbol "_ZNSs4_Rep20_S_empty_rep_storageE@@GLIBCXX_3.4"
编辑:
D_GLIBCXX_FULLY_DYNAMIC_STRING
宏有点帮助。
现在
my project -O1
: so.file -O0
有效
my project -O1
: so.file -O1
失败
问题
我没有这些库的代码。
我想知道我还能做些什么来解决这个问题。
调查的下一步应该是什么?
What should be next steps in investigation?
你应该开始调试了。通常 -O0
的错误 "get away it" 只会在优化稍微启动时受到严重打击。
因为我不知道你的代码我只能猜测。
我假设您创建了某种仅供您的共享库使用的对象。可能是某种样板。你将它传递给你的共享库,它会对其进行一些处理,然后将其删除。
因为您从未在自己的代码中读取此变量,所以编译器很有可能将其优化掉。
要解决您的问题,您必须找到该特定变量并将其标记为 volatile
以防止它被优化掉。
祝你好运。
$ c++filt _ZNSs4_Rep20_S_empty_rep_storageE
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_S_empty_rep_storage
_S_empty_rep_storage
声明为:
// The following storage is init'd to 0 by the linker, resulting
// (carefully) in an empty string with one reference.
static size_type _S_empty_rep_storage[];
并定义为:
// Linker sets _S_empty_rep_storage to all 0s (one reference, empty string)
// at static init time (before static ctors are run).
template<typename _CharT, typename _Traits, typename _Alloc>
typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::_Rep::_S_empty_rep_storage[
(sizeof(_Rep_base) + sizeof(_CharT) + sizeof(size_type) - 1) /
sizeof(size_type)];
您加载的共享库似乎有另一个(较旧的)_S_empty_rep_storage
定义。在旧版本的 GNU C++ 库中,_S_empty_rep_storage
曾经是动态分配的,这就是共享库尝试执行 delete _S_empty_rep_storage
并崩溃的原因。
解决方法是使用相同的 C++ 编译器和链接器选项针对您使用的 C++ 库重新编译共享库。
我得到了 3-rd pt 库源,结果发现它也执行 dlopen 并出现以下错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42679