将clang 3.5.0与-flto一起使用并链接到共享库时,共享库中对operator delete
的调用似乎与调用operator new
的符号解析顺序不同来自主要对象。例如:
shared.cpp :
void deleteIt(int* ptr) {
delete ptr;
}
的main.cpp :
#include <cstdlib>
#include <new>
void* operator new(size_t size) {
void* result = std::malloc(size);
if (result == nullptr) {
throw std::bad_alloc();
}
return result;
}
void operator delete(void* ptr) noexcept {
std::free(ptr);
}
void deleteIt(int* ptr);
int main() {
deleteIt(new int);
return 0;
}
当我构建并通过valgrind运行它时会发生什么:
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold -fPIC -shared shared.cpp -o libshared.so
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold main.cpp -L. -lshared -o main
$ LD_LIBRARY_PATH=. valgrind --quiet ./main
==20557== Mismatched free() / delete / delete []
==20557== at 0x4C2B6D0: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20557== by 0x4009F7: main (main.cpp:19)
==20557== Address 0x5a03040 is 0 bytes inside a block of size 4 alloc'd
==20557== at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20557== by 0x4009EA: operator new (main.cpp:5)
==20557== by 0x4009EA: main (main.cpp:19)
==20557==
您可以看到它正在找到valgrind的operator delete
,但使用operator new
中的main.cpp
。相比之下,使用gcc完全相同的构建(只需用clang++
替换g++
)就可以了。有什么想法,或者如何解决它?
编辑:符号导入和导出,符合@Deduplicator的要求。
$ objdump -T main | c++filt | grep operator
0000000000400990 g DF .text 0000000000000033 Base operator new(unsigned long)
0000000000000000 DF *UND* 0000000000000000 Base operator delete(void*)
$ objdump -T libshared.so | c++filt | grep operator
0000000000000000 DF *UND* 0000000000000000 GLIBCXX_3.4 operator delete(void*)
答案 0 :(得分:5)
查看object-dump,显然operator delete(void*)
未导出main
。
$ objdump -T main | c++filt | grep operator
0000000000400990 g DF .text 0000000000000033 Base operator new(unsigned long)
0000000000000000 DF *UND* 0000000000000000 Base operator delete(void*)
请注意operator delete(void*)
存储的部分是*UND*
:它不存在!
现在,对于clang来说,这是一个明显的失败,可能是一个很好的错误报告,因为我们已经有了一个最小的测试用例。
现在,如何强迫clang保持并导出operator delete(void*)
作为创可贴?
答案是looking at the possible attributes,有一个很好的答案:
使用
附加到函数的此属性意味着即使看起来函数未被引用,也必须为函数发出代码。例如,仅在内联汇编中引用该函数时,这很有用。 当应用于C ++类模板的成员函数时,该属性还意味着如果实例化类本身,则实例化该函数。
将其放入代码中:
void operator delete(void* ptr) noexcept __attribute__((used)) {
瞧瞧,铿锵不再不正当地修剪它。