Index: lib/asan/CMakeLists.txt =================================================================== --- lib/asan/CMakeLists.txt +++ lib/asan/CMakeLists.txt @@ -181,6 +181,7 @@ if (WIN32) add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC SOURCES asan_dll_thunk.cc + $ CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK DEFS ${ASAN_COMMON_DEFINITIONS}) add_dependencies(asan clang_rt.asan_dll_thunk-${arch}) Index: lib/asan/asan_dll_thunk.cc =================================================================== --- lib/asan/asan_dll_thunk.cc +++ lib/asan/asan_dll_thunk.cc @@ -20,6 +20,7 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DLL_THUNK +#include "sanitizer_common/sanitizer_interception.h" // ----------------- Helper functions and macros --------------------- {{{1 extern "C" { @@ -115,7 +116,50 @@ } // }}} +// --------- Interface interception helper functions and macros ----------- {{{1 +// We need to intercept the ASan interface exported by the DLL thunk and forward +// all the functions to the runtime in the main module. +// However, we don't want to keep two lists of interface functions. +// To avoid that, the list of interface functions should be defined using the +// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once +// by calling INTERCEPT_ASAN_INTERFACE(). + +// Use macro+template magic to automatically generate the list of interface +// functions. Each interface function at line LINE defines a template class +// with a static InterfaceInteceptor::Execute() method intercepting the +// function. The default implementation of InterfaceInteceptor is to call +// the Execute() method corresponding to the previous line. +template +struct InterfaceInteceptor { + static void Execute() { InterfaceInteceptor::Execute(); } +}; + +// There shouldn't be any interface function with negative line number. +template<> +struct InterfaceInteceptor<0> { + static void Execute() {} +}; + +#define INTERFACE_FUNCTION(name) \ + extern "C" void name() { __debugbreak(); } \ + template<> struct InterfaceInteceptor<__LINE__> { \ + static void Execute() { \ + void *wrapper = getRealProcAddressOrDie(#name); \ + if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0)) \ + abort(); \ + InterfaceInteceptor<__LINE__-1>::Execute(); \ + } \ + }; + +// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION. +#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute + +static void InterceptASanInterface(); +// }}} + // ----------------- ASan own interface functions -------------------- +// Don't use the INTERFACE_FUNCTION machinery for this function as we actually +// want to call it in the __asan_init interceptor. WRAP_W_V(__asan_should_detect_stack_use_after_return) extern "C" { @@ -125,70 +169,75 @@ // __asan_option_detect_stack_use_after_return afterwards. void __asan_init_v3() { typedef void (*fntype)(); - static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); + static fntype fn = 0; + if (fn) return; + + fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); + + InterceptASanInterface(); } } -WRAP_V_V(__asan_handle_no_return) - -WRAP_V_W(__asan_report_store1) -WRAP_V_W(__asan_report_store2) -WRAP_V_W(__asan_report_store4) -WRAP_V_W(__asan_report_store8) -WRAP_V_W(__asan_report_store16) -WRAP_V_WW(__asan_report_store_n) - -WRAP_V_W(__asan_report_load1) -WRAP_V_W(__asan_report_load2) -WRAP_V_W(__asan_report_load4) -WRAP_V_W(__asan_report_load8) -WRAP_V_W(__asan_report_load16) -WRAP_V_WW(__asan_report_load_n) - -WRAP_W_WWW(__asan_memcpy); -WRAP_W_WWW(__asan_memset); -WRAP_W_WWW(__asan_memmove); - -WRAP_V_WW(__asan_register_globals) -WRAP_V_WW(__asan_unregister_globals) - -WRAP_V_W(__asan_before_dynamic_init) -WRAP_V_V(__asan_after_dynamic_init) - -WRAP_V_WW(__asan_poison_stack_memory) -WRAP_V_WW(__asan_unpoison_stack_memory) - -WRAP_V_WW(__asan_poison_memory_region) -WRAP_V_WW(__asan_unpoison_memory_region) - -WRAP_W_V(__asan_get_current_fake_stack) -WRAP_W_WWWW(__asan_addr_is_in_fake_stack) - -WRAP_W_WW(__asan_stack_malloc_0) -WRAP_W_WW(__asan_stack_malloc_1) -WRAP_W_WW(__asan_stack_malloc_2) -WRAP_W_WW(__asan_stack_malloc_3) -WRAP_W_WW(__asan_stack_malloc_4) -WRAP_W_WW(__asan_stack_malloc_5) -WRAP_W_WW(__asan_stack_malloc_6) -WRAP_W_WW(__asan_stack_malloc_7) -WRAP_W_WW(__asan_stack_malloc_8) -WRAP_W_WW(__asan_stack_malloc_9) -WRAP_W_WW(__asan_stack_malloc_10) - -WRAP_V_WWW(__asan_stack_free_0) -WRAP_V_WWW(__asan_stack_free_1) -WRAP_V_WWW(__asan_stack_free_2) -WRAP_V_WWW(__asan_stack_free_4) -WRAP_V_WWW(__asan_stack_free_5) -WRAP_V_WWW(__asan_stack_free_6) -WRAP_V_WWW(__asan_stack_free_7) -WRAP_V_WWW(__asan_stack_free_8) -WRAP_V_WWW(__asan_stack_free_9) -WRAP_V_WWW(__asan_stack_free_10) +INTERFACE_FUNCTION(__asan_handle_no_return) + +INTERFACE_FUNCTION(__asan_report_store1) +INTERFACE_FUNCTION(__asan_report_store2) +INTERFACE_FUNCTION(__asan_report_store4) +INTERFACE_FUNCTION(__asan_report_store8) +INTERFACE_FUNCTION(__asan_report_store16) +INTERFACE_FUNCTION(__asan_report_store_n) + +INTERFACE_FUNCTION(__asan_report_load1) +INTERFACE_FUNCTION(__asan_report_load2) +INTERFACE_FUNCTION(__asan_report_load4) +INTERFACE_FUNCTION(__asan_report_load8) +INTERFACE_FUNCTION(__asan_report_load16) +INTERFACE_FUNCTION(__asan_report_load_n) + +INTERFACE_FUNCTION(__asan_memcpy); +INTERFACE_FUNCTION(__asan_memset); +INTERFACE_FUNCTION(__asan_memmove); + +INTERFACE_FUNCTION(__asan_register_globals) +INTERFACE_FUNCTION(__asan_unregister_globals) + +INTERFACE_FUNCTION(__asan_before_dynamic_init) +INTERFACE_FUNCTION(__asan_after_dynamic_init) + +INTERFACE_FUNCTION(__asan_poison_stack_memory) +INTERFACE_FUNCTION(__asan_unpoison_stack_memory) + +INTERFACE_FUNCTION(__asan_poison_memory_region) +INTERFACE_FUNCTION(__asan_unpoison_memory_region) + +INTERFACE_FUNCTION(__asan_get_current_fake_stack) +INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) + +INTERFACE_FUNCTION(__asan_stack_malloc_0) +INTERFACE_FUNCTION(__asan_stack_malloc_1) +INTERFACE_FUNCTION(__asan_stack_malloc_2) +INTERFACE_FUNCTION(__asan_stack_malloc_3) +INTERFACE_FUNCTION(__asan_stack_malloc_4) +INTERFACE_FUNCTION(__asan_stack_malloc_5) +INTERFACE_FUNCTION(__asan_stack_malloc_6) +INTERFACE_FUNCTION(__asan_stack_malloc_7) +INTERFACE_FUNCTION(__asan_stack_malloc_8) +INTERFACE_FUNCTION(__asan_stack_malloc_9) +INTERFACE_FUNCTION(__asan_stack_malloc_10) + +INTERFACE_FUNCTION(__asan_stack_free_0) +INTERFACE_FUNCTION(__asan_stack_free_1) +INTERFACE_FUNCTION(__asan_stack_free_2) +INTERFACE_FUNCTION(__asan_stack_free_4) +INTERFACE_FUNCTION(__asan_stack_free_5) +INTERFACE_FUNCTION(__asan_stack_free_6) +INTERFACE_FUNCTION(__asan_stack_free_7) +INTERFACE_FUNCTION(__asan_stack_free_8) +INTERFACE_FUNCTION(__asan_stack_free_9) +INTERFACE_FUNCTION(__asan_stack_free_10) // TODO(timurrrr): Add more interface functions on the as-needed basis. @@ -216,4 +265,8 @@ // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). + void InterceptASanInterface() { + INTERCEPT_ASAN_INTERFACE(); + } + #endif // ASAN_DLL_THUNK Index: test/asan/TestCases/Windows/dll_malloc_left_oob.cc =================================================================== --- test/asan/TestCases/Windows/dll_malloc_left_oob.cc +++ test/asan/TestCases/Windows/dll_malloc_left_oob.cc @@ -10,12 +10,13 @@ buffer[-1] = 42; // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T0 -// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]] +// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]] // CHECK-NEXT: main {{.*}}dll_host.cc +// // CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region // CHECK-LABEL: allocated by thread T0 here: // CHECK: malloc -// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-9]] +// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]] // CHECK-NEXT: main {{.*}}dll_host.cc // CHECK-LABEL: SUMMARY free(buffer); Index: test/asan/TestCases/Windows/dll_malloc_uaf.cc =================================================================== --- test/asan/TestCases/Windows/dll_malloc_uaf.cc +++ test/asan/TestCases/Windows/dll_malloc_uaf.cc @@ -7,21 +7,23 @@ extern "C" __declspec(dllexport) int test_function() { - char *buffer = (char*)malloc(42); + int *buffer = (int*)malloc(42); free(buffer); buffer[0] = 42; // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]] -// CHECK: WRITE of size 1 at [[ADDR]] thread T0 -// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]] +// CHECK: WRITE of size 4 at [[ADDR]] thread T0 +// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]] // CHECK-NEXT: main {{.*}}dll_host +// // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region // CHECK-LABEL: freed by thread T0 here: // CHECK: free -// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-9]] +// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]] // CHECK-NEXT: main {{.*}}dll_host +// // CHECK-LABEL: previously allocated by thread T0 here: // CHECK: malloc -// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-14]] +// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]] // CHECK-NEXT: main {{.*}}dll_host return 0; } Index: test/asan/TestCases/Windows/dll_noreturn.cc =================================================================== --- test/asan/TestCases/Windows/dll_noreturn.cc +++ test/asan/TestCases/Windows/dll_noreturn.cc @@ -12,9 +12,10 @@ _exit(1); // CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T0 -// CHECK: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]] +// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]] // CHECK-NEXT: test_function {{.*}}dll_noreturn.cc // CHECK-NEXT: main {{.*}}dll_host.cc +// // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc // CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable Index: test/asan/TestCases/Windows/dll_poison_unpoison.cc =================================================================== --- test/asan/TestCases/Windows/dll_poison_unpoison.cc +++ test/asan/TestCases/Windows/dll_poison_unpoison.cc @@ -25,9 +25,10 @@ should_crash(&buffer[96]); // CHECK: AddressSanitizer: use-after-poison on address [[ADDR:0x[0-9a-f]+]] // CHECK-NEXT: WRITE of size 1 at [[ADDR]] thread T0 -// CHECK: should_crash {{.*}}\dll_poison_unpoison.cc +// CHECK-NEXT: should_crash {{.*}}\dll_poison_unpoison.cc // CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc:[[@LINE-4]] // CHECK-NEXT: main +// // CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc // CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable Index: test/asan/TestCases/Windows/dll_stack_use_after_return.cc =================================================================== --- test/asan/TestCases/Windows/dll_stack_use_after_return.cc +++ test/asan/TestCases/Windows/dll_stack_use_after_return.cc @@ -18,8 +18,9 @@ *x = 42; // CHECK: AddressSanitizer: stack-use-after-return // CHECK: WRITE of size 1 at [[ADDR:.*]] thread T0 -// CHECK: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]] +// CHECK-NEXT: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]] // CHECK-NEXT: main +// // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame // CHECK-NEXT: #0 {{.*}} foo {{.*}}dll_stack_use_after_return.cc // CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable Index: test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc =================================================================== --- test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc +++ test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc @@ -12,9 +12,11 @@ stack_buffer[subscript] = 42; // CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T1 -// CHECK: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]] +// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]] +// // CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame -// CHECK: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc +// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc +// // CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable return 0;