https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63888
--- Comment #21 from Jakub Jelinek <jakub at gcc dot gnu.org> --- (In reply to Kostya Serebryany from comment #20) > > Is this clear? This is on access of the b1 variable defined in main.c, > > certainly not anything around f variable defined in libfoo.c. > > Yea. Thanks. Pondering... > I am still not convinced that this code is good (even if it is > C-standard-compliant). Various programs do it, this is normal ELF symbol interposition. Of course more often people interpose functions than variables (after all, all of libasan relies heavily on it, and also violates C++ ODR by doing that), but it happens even for variables. And, more importantly, the diagnostics is completely confusing. If it wasn't for the recently added ODR checking, I'd say GCC will keep what it is doing and in LLVM it is up to you what you want to do. But the ODR checking relies on the implementation choice of LLVM, which makes it a problem for GCC too. Consider another testcase, without ANY duplicate symbol definition in there, I think you can't find anything not kosher on it. $ cat libfoo.c long f = 4; long g = 5; long foo (long *p) { return *p; } $ cat libfoo2.c long h = 12, i = 13; $ cat main2.c extern void abort (void); extern long f; extern long h; extern long i; long foo (long *); int main () { if (foo (&f) != 4 || foo (&h) != 12 || foo (&i) != 13) abort (); return 0; } $ gcc -g -shared -fpic -o libfoo.{so,c} $ gcc -g -shared -fpic -o libfoo2.{so,c} $ gcc -c -g -o main2.{o,c} $ gcc -fsanitize=address -o main2{,.o} ./libfoo.so ./libfoo2.so $ ./main2; echo $? 0 $ gcc -fsanitize=address -g -shared -fpic -o libfoo.{so,c} $ ./main2; echo $? 0 $ clang -g -shared -fpic -o libfoo.{so,c} $ clang -g -shared -fpic -o libfoo2.{so,c} $ clang -c -g -o main2.{o,c} $ clang -fsanitize=address -o main2{,.o} ./libfoo.so ./libfoo2.so $ ./main2; echo $? 0 $ clang -fsanitize=address -g -shared -fpic -o libfoo.{so,c} $ ./main2; echo $? ./main2: Symbol `f' has different size in shared object, consider re-linking ================================================================= ==5791==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000006dca10 at pc 0x7f6601b17b94 bp 0x7fff63d1ebb0 sp 0x7fff63d1eba8 READ of size 8 at 0x0000006dca10 thread T0 #0 0x7f6601b17b93 in foo /tmp/libfoo.c:3:22 #1 0x4ba273 in main /tmp/main2.c:10:42 #2 0x327981ffdf in __libc_start_main (/lib64/libc.so.6+0x327981ffdf) #3 0x4341f6 in _start (/tmp/main2+0x4341f6) 0x0000006dca10 is located 0 bytes to the right of global variable 'f' defined in 'libfoo.c:1:6' (0x6dca08) of size 8 SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/libfoo.c:3 foo Shadow bytes around the buggy address: 0x0000800d38f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0000800d3940: 00 00[f9]f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 0x0000800d3950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800d3990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==5791==ABORTING 1 That shows not just that not using the local aliases is bad, but it is also bad to use incorrect sizes of the variables. In gcc produced sanitized libfoo.so the f and g symbols have st_size still 8, the padding is included after the symbol, but not included in the size of the symbol. In llvm, the padding is included in st_size, so f and g symbols have st_size of 64, making it ABI incompatible (both ways, either a binary linked against -fsanitize=address compiled library later run against non-sanitized one results in larger size allocated in .dynbss and you get a dynamic linker warning, or binary linked against non-sanitized library later run against sanitized library - this allocates smaller size in .dynbss and then writes over larger size, you get a dynamic linker warning and can get symbols after it poisoned).