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).

Reply via email to