summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2014-07-11 11:57:41 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2014-07-11 11:57:41 +0000
commit65b42e13c28dfc17859db3ba78dc0a4e2a35cb9c (patch)
tree448277709f6a531c8f6ecdba654454b9e3874212
parent4f59148e575e01ed1896ff98f0e8a99ab689ebe5 (diff)
downloadcompiler-rt-65b42e13c28dfc17859db3ba78dc0a4e2a35cb9c.tar.gz
[ASan/Win] Catch NULL derefs and page faults
Reviewed at http://reviews.llvm.org/D4471 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@212807 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_posix.cc2
-rw-r--r--lib/asan/asan_report.cc7
-rw-r--r--lib/asan/asan_report.h4
-rw-r--r--lib/asan/asan_win.cc39
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc30
-rw-r--r--test/asan/TestCases/Windows/null_deref.cc15
6 files changed, 88 insertions, 9 deletions
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 57c958112..da9261998 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -50,7 +50,7 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
(code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(pc, sp, bp, context, addr);
else
- ReportSIGSEGV(pc, sp, bp, context, addr);
+ ReportSIGSEGV("SEGV", pc, sp, bp, context, addr);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index e13d59f88..fb7c8fd09 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -611,14 +611,15 @@ void ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
ReportErrorSummary("stack-overflow", &stack);
}
-void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
+void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
+ void *context, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
Report(
- "ERROR: AddressSanitizer: SEGV on unknown address %p"
+ "ERROR: AddressSanitizer: %s on unknown address %p"
" (pc %p sp %p bp %p T%d)\n",
- (void *)addr, (void *)pc, (void *)sp, (void *)bp,
+ description, (void *)addr, (void *)pc, (void *)sp, (void *)bp,
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
GET_STACK_TRACE_SIGNAL(pc, bp, context);
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 374ebfb4f..bec7f61db 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -34,8 +34,8 @@ void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void NORETURN
ReportStackOverflow(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
-void NORETURN
- ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
+void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
+ void *context, uptr addr);
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index da26e989a..162393c64 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -21,6 +21,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
+#include "asan_report.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -86,6 +87,44 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
UNIMPLEMENTED();
}
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+
+long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
+#else
+ uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
+#endif
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ uptr access_addr = exception_record->ExceptionInformation[1];
+ ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
+ }
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ return default_seh_handler(info);
+}
+
+int SetSEHFilter() {
+ default_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ 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.
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+__declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = SetSEHFilter;
+
} // namespace __asan
#endif // _WIN32
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index da24df684..b7402ee51 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -17,9 +17,10 @@
#define WIN32_LEAN_AND_MEAN
#define NOGDI
-#include <stdlib.h>
-#include <io.h>
#include <windows.h>
+#include <dbghelp.h>
+#include <io.h>
+#include <stdlib.h>
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
@@ -449,7 +450,30 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
uptr max_depth) {
- UNREACHABLE("no signal context on windows");
+ CONTEXT ctx = *(CONTEXT *)context;
+ STACKFRAME64 stack_frame;
+ memset(&stack_frame, 0, sizeof(stack_frame));
+ size = 0;
+#if defined(_WIN64)
+ int machine_type = IMAGE_FILE_MACHINE_AMD64;
+ stack_frame.AddrPC.Offset = ctx.Rip;
+ stack_frame.AddrFrame.Offset = ctx.Rbp;
+ stack_frame.AddrStack.Offset = ctx.Rsp;
+#else
+ int machine_type = IMAGE_FILE_MACHINE_I386;
+ stack_frame.AddrPC.Offset = ctx.Eip;
+ stack_frame.AddrFrame.Offset = ctx.Ebp;
+ stack_frame.AddrStack.Offset = ctx.Esp;
+#endif
+ stack_frame.AddrPC.Mode = AddrModeFlat;
+ stack_frame.AddrFrame.Mode = AddrModeFlat;
+ stack_frame.AddrStack.Mode = AddrModeFlat;
+ while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
+ &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
+ &SymGetModuleBase64, NULL) &&
+ size < Min(max_depth, kStackTraceMax)) {
+ trace[size++] = (uptr)stack_frame.AddrPC.Offset;
+ }
}
void MaybeOpenReportFile() {
diff --git a/test/asan/TestCases/Windows/null_deref.cc b/test/asan/TestCases/Windows/null_deref.cc
new file mode 100644
index 000000000..42172109d
--- /dev/null
+++ b/test/asan/TestCases/Windows/null_deref.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// FIXME: merge this with the common null_deref test when we can run common
+// tests on Windows.
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+ // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK: {{0x0*000.. .*pc 0x.*}}
+ ptr[10]++; // BOOM
+}
+int main() {
+ NullDeref((int*)0);
+ // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
+ // CHECK: {{AddressSanitizer can not provide additional info.}}
+}