Yesterday we saw
how to get line numbers in the stacktrace when using ASAN and gcc, today we're going to see how to deal with ASAN and libraries. For that we're going to use these three very simple files
shared.cpp
#include "shared.h"
Foo::Foo()
{
int *a = 0;
*a = 33;
}
shared.h
class Foo
{
public:
Foo();
};
main.cpp
#include "shared.h"
int main(int, char **)
{
Foo f;
return 0;
}
We do the initial compilation:
g++ -Wl,--no-undefined -shared -o libshared.so shared.cpp -g3
g++ main.cpp -lshared -L . -g3
LD_LIBRARY_PATH=. ./a.out
and it segfaults :)
Now we want to use ASAN to find out what's wrong, where do we add the -fsanitize=address -fno-omit-frame-pointer? Logic would say that we add it to both places, but actually it's only necessary to add it to the final binary, i.e
g++ -Wl,--no-undefined -shared -o libshared.so shared.cpp -g3
g++ -fno-omit-frame-pointer -fsanitize=address main.cpp -lshared -L . -g3
LD_LIBRARY_PATH=. ./a.out
and we get
==10226== ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000
(pc 0x7f497563f66a sp 0x7fff77cc4310 bp 0x7fff77cc4310 T0)
AddressSanitizer can not provide additional info.
#0 0x7f497563f669 in Foo::Foo() /home/tsdgeos/test/shared.cpp:6
#1 0x40074a in main /home/tsdgeos/test/main.cpp:5
#2 0x7f497529aec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#3 0x400638 in _start (/home/tsdgeos/test/a.out+0x400638)
SUMMARY: AddressSanitizer: SEGV /home/tsdgeos/test/shared.cpp:6 Foo::Foo()
There you go, no need to add the -fsanitize=address flag to the library compilation :)
Now, until a few minutes ago I did not know this, I actually was adding -fsanitize=address to the library itself; that comes with a few problems that i'll explain how i solved (just for completeness, since the above example shows you don't need it)
My logic was that by looking at main.cpp i knew nothing could be wrong there so i decided i wanted sanitize the library, my first attempt was:
g++ -Wl,--no-undefined -shared -o libshared.so shared.cpp -g3 \
-fno-omit-frame-pointer -fsanitize=address
which gives a linking error
/tmp/cc18Wen3.o: In function `Foo::Foo()':
/home/tsdgeos/test/shared.cpp:6: undefined reference to `__asan_report_store4'
/usr/bin/ld: /tmp/cc18Wen3.o: relocation R_X86_64_PC32 against undefined symbol
`__asan_report_store4' can not be used when making a shared object;
recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
OK, so we are told to recompile with -fPIC, easy peasy
g++ -Wl,--no-undefined -shared -o libshared.so shared.cpp -g3 \
-fno-omit-frame-pointer -fsanitize=address -fPIC
Which still fails to link!
/tmp/ccNkpRZo.o: In function `Foo::Foo()':
/home/tsdgeos/test/shared.cpp:6: undefined reference to `__asan_report_store4'
/tmp/ccNkpRZo.o: In function `_GLOBAL__sub_I_00099_0_shared.cpp':
/home/tsdgeos/test/shared.cpp:7: undefined reference to `__asan_init_v1'
collect2: error: ld returned 1 exit status
OK, so if ASAN symbols are missing, let's just compile libasan in
g++ -Wl,--no-undefined -shared -o libshared.so shared.cpp -g3 \
-fno-omit-frame-pointer -fsanitize=address -fPIC -lasan
Links!
Next since I know nothing is wrong in main.cpp I don't need ASAN in there
g++ main.cpp -lshared -L . -g3
Compiles!
But when run it segfaults :-/ And if you debug it you'll see a stack trace like
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff4894bf1 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#2 0x00007ffff4894e32 in ?? () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#3 0x00007ffff4895d9b in __asan_init_v1 () from /usr/lib/x86_64-linux-gnu/libasan.so.0
#4 0x00007ffff7bd8776 in _GLOBAL__sub_I_00099_0_shared.cpp(void) () at shared.cpp:7
#5 0x00007ffff7dea13a in call_init (l=, argc=argc@entry=1, argv=argv@entry=0x7fffffffde18, env=env@entry=0x7fffffffde28) at dl-init.c:78
#6 0x00007ffff7dea223 in call_init (env=, argv=, argc=, l=) at dl-init.c:36
#7 _dl_init (main_map=0x7ffff7ffe1c8, argc=1, argv=0x7fffffffde18, env=0x7fffffffde28) at dl-init.c:126
#8 0x00007ffff7ddb30a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#9 0x0000000000000001 in ?? ()
#10 0x00007fffffffe1ca in ?? ()
#11 0x0000000000000000 in ?? ()
So something weird in ASAN thing is going on, let's compile -lasan in also
g++ main.cpp -lshared -L . -g3 -lasan
Same crash :-/
Ok, so then you think, well, let's just add the fsanitize in. And then it works, but as demonstrated a few lines ago, the whole thing of adding -fsanitize=address and -lasan to the library was unneeded since all that was required was just adding -fsanitize=address to the binary when it's compiled and that's it :)