Details
Diff Detail
- Repository
- rL LLVM
- Build Status
Buildable 25639 Build 25638: arc lint + arc unit
Event Timeline
Hm, I'd rather separate private aliases and odr indicators because they are separate (although connected) features:
- Private aliases are used to avoid ASan false positives when we mix instrumented and non-instrumented modules (also, AFAIR, FPs are possible when using LTO). They can be used with and without ODR indicators.
- ODR indicators were introduced to improve ODR violation in presence of private aliases, but they can be omitted if desired.
I'll do this.
- Private aliases are used to avoid ASan false positives when we mix instrumented and non-instrumented modules (also, AFAIR, FPs are possible when using LTO). They can be used with and without ODR indicators.
- ODR indicators were introduced to improve ODR violation in presence of private aliases, but they can be omitted if desired.
Can you please elaborate on how it improves "use_odr_indicator"? Do we miss some violations if we "have aliases without indicators" comparing to default:"have no aliases and have no indicators"?
compiler-rt/test/asan/TestCases/Linux/odr-violation.cc | ||
---|---|---|
29 | Here is a problem. If we just enable -asan-use-private-alias we miss reports which we had on line 10. |
So I am not sure if there is any value in using aliases without indicators.
Oh, this is a long story... In short: if we don't use private aliases, we'll may have ASan false positives when mixing sanitized and non-sanitized code depending on ordering during linkage.
Consider the following example (from https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68016#c8):
max@max:/tmp$ cat libfoo.c long h = 15; long f = 4; long foo (long *p) { return *p; } max@max:/tmp$ cat libbar.c extern void abort (void); long foo (long *); long h = 12; long i = 13; long f = 5; int bar () { if (foo (&f) != 5 || foo (&h) != 12 || foo (&i) != 13) abort (); return 0; } max@max:/tmp$ cat main.c int bar (); int main () { return bar (); } $ clang libfoo.c -shared -fpic -o libfoo.so -g -fsanitize=address $ clang libbar.c -shared -fpic -o libbar.so -g $ clang main.c -c -o main.o $ clang main.o ./libbar.so ./libfoo.so -o main -fsanitize=address $ ./main ==6425==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7efc5f2f2040 at pc 0x7efc5eeef8d1 bp 0x7ffddc2a2ff0 sp 0x7ffddc2a2fe8 READ of size 8 at 0x7efc5f2f2040 thread T0 #0 0x7efc5eeef8d0 in foo /tmp/libfoo.c:4:10 #1 0x7efc5f0f16cf in bar /tmp/libbar.c:8:7 #2 0x4f1575 in main (/tmp/main+0x4f1575) #3 0x7efc5dffc82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291 #4 0x41a378 in _start (/tmp/main+0x41a378) 0x7efc5f2f2040 is located 0 bytes inside of global variable 'f' defined in 'libfoo.c:2:6' (0x7efc5f2f2040) of size 8 0x7efc5f2f2040 is located 8 bytes to the right of global variable 'h' defined in 'libfoo.c:1:6' (0x7efc5f2f2030) of size 8 SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/libfoo.c:4:10 in foo Shadow bytes around the buggy address: 0x0fe00be563b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be563c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be563d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be563e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be563f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0fe00be56400: 00 00 00 00 00 00 00 f9[f9]f9 f9 f9 f9 f9 f9 f9 0x0fe00be56410: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be56420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be56430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be56440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0fe00be56450: 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 Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 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 Left alloca redzone: ca Right alloca redzone: cb ==6425==ABORTING
Here, global symbols 'f' and 'h' are resolved to libbar.so, that is not sanitized. However, when libfoo.so registers its "own" globals, it actually poisons libbar.so's 'f' and 'h' that are not properly padded.
There also was an issue with LTO, see https://github.com/google/sanitizers/issues/647
We can use private aliases w/o indicators if we don't care about ODR violation and don't want to pay for odr indicators size.
Can you please elaborate on how it improves "use_odr_indicator"? Do we miss some violations if we "have aliases without indicators" comparing to default:"have no aliases and have no indicators"?
Here is a problem. If we just enable -asan-use-private-alias we miss reports which we had on line 10.
That's correct. Right now detector relies on fact that if we have an ODR violation for some pair of globals, when we register the second one, its will be already poisoned (this will be true at least for ELF). So, effectively it checks that we try to poison the same global twice.
However, this won't be the case when we use private aliases, because we won't try to poison one global twice, we'll poison their private aliases that reside in their corresponding DSOs. In this case, even when we have actual ODR violation, we won't be able to catch it.
And here odr indicators come -- they mimic original globals and allow us to detect ODR violation in a pretty similar manner as before, but without poisoning innocent globals from non-instrumented DSOs.
Here is a problem. If we just enable -asan-use-private-alias we miss reports which we had on line 10.
So I am not sure if there is any value in using aliases without indicators.