When using clang 3.5.0 with -flto and linking with a shared library, it seems that calls to operator delete
in the shared library don't follow the same symbol resolution order as calls to operator new
from the main objects. Example:
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;
}
Here's what happens when I build it and run it through 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==
You can see that it's finding the valgrind's operator delete
, but using operator new
from main.cpp
. In contrast, the exact same build with gcc (just replace clang++
with g++
) works fine. Any ideas why, or how to work around it?
EDIT: Symbol imports and exports, as requested by @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*)