diff options
| author | Etienne Bergeron <etienneb@google.com> | 2017-02-21 20:04:47 +0000 |
|---|---|---|
| committer | Etienne Bergeron <etienneb@google.com> | 2017-02-21 20:04:47 +0000 |
| commit | 0eec53cb41523790c47e6d1d4a9c98c15d33e9b6 (patch) | |
| tree | 71714db06550a09518d6f4c158f5d5c51b8c47a0 | |
| parent | 43313b3e89277f931490edb42689f173079a2dc6 (diff) | |
| download | bcm5719-llvm-0eec53cb41523790c47e6d1d4a9c98c15d33e9b6.tar.gz bcm5719-llvm-0eec53cb41523790c47e6d1d4a9c98c15d33e9b6.zip | |
[compiler-rt][asan] Fix incorrect macro preventing ICF with MSVC
Summary:
The DLL thunks are stubs added to an instrumented DLL to redirect ASAN API calls
to the real ones in the main executable. These thunks must contain dummy
code before __asan_init got called. Unfortunately, MSVC linker is doing ICF and is
merging functions with the same body.
In our case, this two ASAN thunks were incorrectly merged:
```
asan_interface.inc:16
INTERFACE_FUNCTION(__asan_before_dynamic_init)
```
```
sanitizer_common_interface.inc:16
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
```
The same thunk got patched twice. After the second patching, calls to
`__asan_before_dynamic_init` are redirected to `__sanitizer_verify_contiguous_container`
and trigger a DCHECK on incorrect operands/
The problem was caused by the macro that is only using __LINE__ to prevent
collapsing code.
```
#define INTERCEPT_SANITIZER_FUNCTION(name)
extern "C" __declspec(noinline) void name() {
volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf;
```
The current patch is adding __COUNTER__ which is safer than __LINE__.
Also, to precent ICF (guarantee that code is different), we are using a unique attribute:
- the name of the function
Reviewers: rnk
Reviewed By: rnk
Subscribers: llvm-commits, kubamracek, chrisha, dberris
Differential Revision: https://reviews.llvm.org/D30219
llvm-svn: 295761
| -rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h index 00a3b023dd8..2f9ebdaa6e7 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h @@ -53,7 +53,11 @@ extern "C" int __dll_thunk_init(); // after __asan_init, thus an empty implementation is sufficient. #define INTERCEPT_SANITIZER_FUNCTION(name) \ extern "C" __declspec(noinline) void name() { \ - volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ + volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ + static const char function_name[] = #name; \ + for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ + prevent_icf ^= *ptr; \ + (void)prevent_icf; \ __debugbreak(); \ } \ INTERCEPT_OR_DIE(#name, name) @@ -64,7 +68,11 @@ extern "C" int __dll_thunk_init(); // we consider the default impl provided by asan library. #define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \ extern "C" __declspec(noinline) void name() { \ - volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ + volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ + static const char function_name[] = #name; \ + for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ + prevent_icf ^= *ptr; \ + (void)prevent_icf; \ __debugbreak(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name) |

