[compiler-rt] r217679 - [ASan/Win] Fix PR20918 -- SEH handler doesn't work with the MD runtime

Timur Iskhodzhanov timurrrr at google.com
Fri Sep 12 07:01:31 PDT 2014


Author: timurrrr
Date: Fri Sep 12 09:01:30 2014
New Revision: 217679

URL: http://llvm.org/viewvc/llvm-project?rev=217679&view=rev
Log:
[ASan/Win] Fix PR20918 -- SEH handler doesn't work with the MD runtime

Added:
    compiler-rt/trunk/test/asan/TestCases/Windows/dll_null_deref.cc
    compiler-rt/trunk/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_win.cc
    compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc

Modified: compiler-rt/trunk/lib/asan/asan_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win.cc?rev=217679&r1=217678&r2=217679&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win.cc Fri Sep 12 09:01:30 2014
@@ -89,7 +89,7 @@ void AsanOnSIGSEGV(int, void *siginfo, v
 
 static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
 
-long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
   EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
   CONTEXT *context = info->ContextRecord;
   uptr pc = (uptr)exception_record->ExceptionAddress;
@@ -114,16 +114,39 @@ long WINAPI SEHHandler(EXCEPTION_POINTER
   return default_seh_handler(info);
 }
 
-int SetSEHFilter() {
-  default_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+// We want to install our own exception handler (EH) to print helpful reports
+// on access violations and whatnot.  Unfortunately, the CRT initializers assume
+// they are run before any user code and drop any previously-installed EHs on
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module.  This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+  // We should only store the previous handler if it's not our own handler in
+  // order to avoid loops in the EH chain.
+  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+  if (prev_seh_handler != &SEHHandler)
+    default_seh_handler = prev_seh_handler;
   return 0;
 }
 
-// Put a pointer to SetSEHFilter at the end of the global list
-// of C initializers, after the default handler is set by the CRT.
-// See crt0dat.c in the CRT sources for the details.
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
 #pragma section(".CRT$XIZ", long, read)  // NOLINT
-__declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = SetSEHFilter;
+static __declspec(allocate(".CRT$XIZ"))
+    int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
 
 }  // namespace __asan
 

Modified: compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc?rev=217679&r1=217678&r2=217679&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc Fri Sep 12 09:01:30 2014
@@ -15,7 +15,7 @@
 //
 // This includes:
 //  - forwarding the detect_stack_use_after_return runtime option
-//  - FIXME: installing a custom SEH handler (PR20918)
+//  - installing a custom SEH handler
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,6 +24,7 @@
 // simplifies the build procedure.
 #ifdef ASAN_DYNAMIC_RUNTIME_THUNK
 extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
 __declspec(dllimport) int __asan_should_detect_stack_use_after_return();
 
 // Define a copy of __asan_option_detect_stack_use_after_return that should be
@@ -38,5 +39,14 @@ __declspec(dllimport) int __asan_should_
 // constant after initialization anyways.
 int __asan_option_detect_stack_use_after_return =
     __asan_should_detect_stack_use_after_return();
+
+// Set the ASan-specific SEH handler at the end of CRT initialization of each
+// module (see asan_win.cc for the details).
+//
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+#pragma section(".CRT$XIZ", long, read)  // NOLINT
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
 }
 #endif // ASAN_DYNAMIC_RUNTIME_THUNK

Added: compiler-rt/trunk/test/asan/TestCases/Windows/dll_null_deref.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/dll_null_deref.cc?rev=217679&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/dll_null_deref.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_null_deref.cc Fri Sep 12 09:01:30 2014
@@ -0,0 +1,18 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK:   {{0x0*000.. .*pc 0x.*}}
+  ptr[10]++;  // BOOM
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in test_function .*\dll_null_deref.cc:}}[[@LINE-1]]
+  // CHECK: AddressSanitizer can not provide additional info.
+  return 0;
+}

Added: compiler-rt/trunk/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc?rev=217679&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc Fri Sep 12 09:01:30 2014
@@ -0,0 +1,40 @@
+// Make sure everything works even if the main module doesn't have any stack
+// variables, thus doesn't explicitly reference any symbol exported by the
+// runtime thunk.
+//
+// RUN: %clang_cl_asan -LD -O0 -DDLL1 %s -Fe%t1.dll
+// RUN: %clang_cl_asan -LD -O0 -DDLL2 %s -Fe%t2.dll
+// RUN: %clang_cl_asan -O0 -DEXE %s %t1.lib %t2.lib -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+#include <string.h>
+
+extern "C" {
+#if defined(EXE)
+__declspec(dllimport) void foo1();
+__declspec(dllimport) void foo2();
+
+int main() {
+  foo1();
+  foo2();
+}
+#elif defined(DLL1)
+__declspec(dllexport) void foo1() {}
+#elif defined(DLL2)
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+  // CHECK:   {{0x0*000.. .*pc 0x.*}}
+  ptr[10]++;  // BOOM
+}
+
+__declspec(dllexport) void foo2() {
+  NullDeref((int*)0);
+  // CHECK: {{    #1 0x.* in foo2.*null_deref_multiple_dlls.cc:}}[[@LINE-1]]
+  // CHECK: AddressSanitizer can not provide additional info.
+}
+#else
+# error oops!
+#endif
+}





More information about the llvm-commits mailing list