From 65b42e13c28dfc17859db3ba78dc0a4e2a35cb9c Mon Sep 17 00:00:00 2001 From: Timur Iskhodzhanov Date: Fri, 11 Jul 2014 11:57:41 +0000 Subject: [PATCH] [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 --- lib/asan/asan_posix.cc | 2 +- lib/asan/asan_report.cc | 7 +++--- lib/asan/asan_report.h | 4 ++-- lib/asan/asan_win.cc | 39 +++++++++++++++++++++++++++++++ lib/sanitizer_common/sanitizer_win.cc | 30 +++++++++++++++++++++--- test/asan/TestCases/Windows/null_deref.cc | 15 ++++++++++++ 6 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 test/asan/TestCases/Windows/null_deref.cc 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 -#include #include +#include +#include +#include #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.}} +} -- 2.11.4.GIT