As discussed in https://github.com/google/sanitizers/issues/398, with current implementation of poisoning globals we can have some CHECK failures or false positives in case of mixing instrumented and non-instrumented code due to ASan poisons innocent globals from non-sanitized binary/library. We can use private aliases to avoid such errors. In addition, to preserve ODR violation detection, we introduce new _asan_genXXX symbol for each instrumented global that indicates if this global was already registered. To detect ODR violation in runtime, we should only check the value of indicator and report an error if it's not equal to zero.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
The change in general makes sense, but is potentially very intrusive, and hard to test on the small set of unit tests.
We'll need to test it on a larger code base. Did you test it on something large?
I afraid Chromium tests are not an adequate test target for this functionality, but it would be a good start.
Alexey, WDYT?
One way I can see is to put this functionality under a combination of a compile-time and a run-time flags.
That'll bloat the code, but I can't see a better way to test it (other than applying the patch locally).
__asan_global will need to be changed unconditionally, but that's ok.
Also, please don't mention the bugs in the source -- it's enough to mention them in the commit message.
Yeah, you are right, the change seems to be intrusive. I ran Chromium tests with the patch and hit on -fvisibililty=hidden stuff (we should not export _asan_genXXX symbols for hidden globals), so we should be very careful here. I'm updating the diff.
As for something really big, I thought Android would be a good candidate (AFAIK, Eugeni hit on ODR fiasco there), but I'm not sure I can build and run it without help (at least I don't have a target device). It would be nice if you could help me here somehow.
Changing symbol linkage basing on visibility attribute is not intuitive and error prone. Instead, we should just copy attributes from NewGlobal to new indicator symbol. However, if we use asan_* pattern, we end up with indicator to be always exported because of --dynamic-list=/usr/local/bin/../lib/clang/3.8.0/lib/linux/libclang_rt.asan-x86_64.a.syms link option and this file contains asan_*. So, just add new __odr_gen* pattern and use it for ODR indicators.
Back here. Hide using private aliases for globals behind -asan-use-private-alias compile option. Generate ODR indicator symbol if use aliases and pass it's address to Global structure, pass 0 otherwise. Tested on Chromium (build chrome itself, build and run unit tests).
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1399 ↗ | (On Diff #45279) | Yes, you are right, perhaps something like this: bool CanUsePrivateAliases = TargetTriple.isOSBinFormatELF(); if (CanUsePrivateAliases && ClUsePrivateAliasForGlobals) { ... ? |
1408 ↗ | (On Diff #45279) | I use ODRIndicatorSym->copyAttributesFrom() that would be inaccessible if use ODRIndicator (that is Constant *). Perhaps we can change it's type to support copyAttributesFrom() interface, but I failed to find reasonable default value for it. If use Constant *, we can just use zero. |
Guys, what do you think? This is complex but we see no other way to robustly support globals.
Sorry for delayed response. Please add an LLVM test for this instrumentation.
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
104 ↗ | (On Diff #45405) | Consider naming this to __asan_odr_gen, so that we could know that these new globals are smth. added by ASan. |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
104 ↗ | (On Diff #45405) | I'd like to, but I hit on this in Firefox: ASan explicitly exports all __asan_* symbols and if we compile our code with e.g -fvisibility=hidden, we can have false positive ODR violation errors. |
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
104 ↗ | (On Diff #45405) | Oh, I see... __odr_asan_gen_ ? :) |
Updating according to Alexey's review.
I've also realized, that we should not copy all attributes from NewGlobal (e.g. we don't need it's alignment and section name) to ODR indicator symbol (thanks Yura for pointing to this!), we just need some of them (Visibility, DLLStorageClass and ThreadLocalMode). Full list of attributes available for copying is here:
LinkageType (set in constructor) VisibilityType DLLStorageClassType Section Alignment ThreadLocalMode (set in constructor) isExternallyInitialized (set in constructor)
Does this look better now?
LGTM
lib/Transforms/Instrumentation/AddressSanitizer.cpp | ||
---|---|---|
1412 ↗ | (On Diff #47006) | Side note: M.getName() might not be unique when you compile/link together a bunch of source files. It shouldn't be relevant here, as global has internal linkage. |
test/Instrumentation/AddressSanitizer/local_alias.ll | ||
26 ↗ | (On Diff #47006) | Do you actually need two functions in this test? |