[ASan/Win] Handle SEH exceptions (best-effort, similar to longjmp)
authorTimur Iskhodzhanov <timurrrr@google.com>
Tue, 22 Jul 2014 13:44:18 +0000 (13:44 +0000)
committerTimur Iskhodzhanov <timurrrr@google.com>
Tue, 22 Jul 2014 13:44:18 +0000 (13:44 +0000)
llvm-svn: 213654

compiler-rt/lib/asan/asan_interceptors.cc
compiler-rt/lib/asan/asan_report.cc
compiler-rt/test/asan/TestCases/Windows/seh.cc [new file with mode: 0644]

index 3638317..23320dc 100644 (file)
@@ -301,6 +301,12 @@ INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
   __asan_handle_no_return();
   REAL(RaiseException)(a, b, c, d);
 }
+
+INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
+  CHECK(REAL(_except_handler3));
+  __asan_handle_no_return();
+  return REAL(_except_handler3)(a, b, c, d);
+}
 #endif
 
 #if ASAN_INTERCEPT_MLOCKX
@@ -737,6 +743,7 @@ namespace __asan {
 void InitializeWindowsInterceptors() {
   ASAN_INTERCEPT_FUNC(CreateThread);
   ASAN_INTERCEPT_FUNC(RaiseException);
+  ASAN_INTERCEPT_FUNC(_except_handler3);
 }
 
 }  // namespace __asan
index 395cefe..19bd79d 100644 (file)
@@ -427,8 +427,12 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
                                   prev_var_end, next_var_beg);
   }
   Printf("HINT: this may be a false positive if your program uses "
-             "some custom stack unwind mechanism or swapcontext\n"
-             "      (longjmp and C++ exceptions *are* supported)\n");
+         "some custom stack unwind mechanism or swapcontext\n");
+  if (SANITIZER_WINDOWS)
+    Printf("      (longjmp, SEH and C++ exceptions *are* supported)\n");
+  else
+    Printf("      (longjmp and C++ exceptions *are* supported)\n");
+
   DescribeThread(t);
   return true;
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/seh.cc b/compiler-rt/test/asan/TestCases/Windows/seh.cc
new file mode 100644 (file)
index 0000000..8730dde
--- /dev/null
@@ -0,0 +1,51 @@
+// Clang doesn't support SEH on Windows yet, so for the time being we
+// build this program in two parts: the code with SEH is built with CL,
+// the rest is built with Clang.  This represents the typical scenario when we
+// build a large project using "clang-cl -fallback -fsanitize=address".
+//
+// RUN: cl -Zi -FS -GS- -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+
+// Should just "#include <sanitizer/asan_interface.h>" when C++ exceptions are
+// supported and we don't need to use CL.
+extern "C" bool __asan_address_is_poisoned(void *p);
+
+void ThrowAndCatch();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+  int local, zero = 0;
+  fprintf(stderr, "Throw:  %p\n", &local);
+  local = 5 / zero;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+  int local;
+  __try {
+    Throw();
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    fprintf(stderr, "__except:  %p\n", &local);
+  }
+}
+#else
+
+int main() {
+  char x[32];
+  fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+          __asan_address_is_poisoned(x + 32));
+  assert(__asan_address_is_poisoned(x + 32));
+  ThrowAndCatch();
+  fprintf(stderr, "After:  %p poisoned: %d\n",  &x,
+          __asan_address_is_poisoned(x + 32));
+  // FIXME: Invert this assertion once we fix
+  // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+  assert(!__asan_address_is_poisoned(x + 32));
+}
+#endif