1//===-- asan_win.cc -------------------------------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is a part of AddressSanitizer, an address sanity checker.
9//
10// Windows-specific details.
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_common/sanitizer_platform.h"
14#if SANITIZER_WINDOWS
15#include <windows.h>
16
17#include <dbghelp.h>
18#include <stdlib.h>
19
20#include "asan_interceptors.h"
21#include "asan_internal.h"
22#include "asan_report.h"
23#include "asan_thread.h"
24#include "sanitizer_common/sanitizer_libc.h"
25#include "sanitizer_common/sanitizer_mutex.h"
26
27extern "C" {
28  SANITIZER_INTERFACE_ATTRIBUTE
29  int __asan_should_detect_stack_use_after_return() {
30    __asan_init();
31    return __asan_option_detect_stack_use_after_return;
32  }
33}
34
35namespace __asan {
36
37// ---------------------- TSD ---------------- {{{1
38static bool tsd_key_inited = false;
39
40static __declspec(thread) void *fake_tsd = 0;
41
42void AsanTSDInit(void (*destructor)(void *tsd)) {
43  // FIXME: we're ignoring the destructor for now.
44  tsd_key_inited = true;
45}
46
47void *AsanTSDGet() {
48  CHECK(tsd_key_inited);
49  return fake_tsd;
50}
51
52void AsanTSDSet(void *tsd) {
53  CHECK(tsd_key_inited);
54  fake_tsd = tsd;
55}
56
57void PlatformTSDDtor(void *tsd) {
58  AsanThread::TSDDtor(tsd);
59}
60// ---------------------- Various stuff ---------------- {{{1
61void MaybeReexec() {
62  // No need to re-exec on Windows.
63}
64
65void *AsanDoesNotSupportStaticLinkage() {
66#if defined(_DEBUG)
67#error Please build the runtime with a non-debug CRT: /MD or /MT
68#endif
69  return 0;
70}
71
72void AsanCheckDynamicRTPrereqs() {}
73
74void AsanCheckIncompatibleRT() {}
75
76void AsanPlatformThreadInit() {
77  // Nothing here for now.
78}
79
80void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
81  UNIMPLEMENTED();
82}
83
84void AsanOnSIGSEGV(int, void *siginfo, void *context) {
85  UNIMPLEMENTED();
86}
87
88static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
89
90static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
91  EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
92  CONTEXT *context = info->ContextRecord;
93  uptr pc = (uptr)exception_record->ExceptionAddress;
94#ifdef _WIN64
95  uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
96#else
97  uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
98#endif
99
100  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
101      exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
102    const char *description =
103        (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
104            ? "access-violation"
105            : "in-page-error";
106    uptr access_addr = exception_record->ExceptionInformation[1];
107    ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
108  }
109
110  // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
111
112  return default_seh_handler(info);
113}
114
115// We want to install our own exception handler (EH) to print helpful reports
116// on access violations and whatnot.  Unfortunately, the CRT initializers assume
117// they are run before any user code and drop any previously-installed EHs on
118// the floor, so we can't install our handler inside __asan_init.
119// (See crt0dat.c in the CRT sources for the details)
120//
121// Things get even more complicated with the dynamic runtime, as it finishes its
122// initialization before the .exe module CRT begins to initialize.
123//
124// For the static runtime (-MT), it's enough to put a callback to
125// __asan_set_seh_filter in the last section for C initializers.
126//
127// For the dynamic runtime (-MD), we want link the same
128// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
129// will be called for each instrumented module.  This ensures that at least one
130// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
131extern "C" SANITIZER_INTERFACE_ATTRIBUTE
132int __asan_set_seh_filter() {
133  // We should only store the previous handler if it's not our own handler in
134  // order to avoid loops in the EH chain.
135  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
136  if (prev_seh_handler != &SEHHandler)
137    default_seh_handler = prev_seh_handler;
138  return 0;
139}
140
141#if !ASAN_DYNAMIC
142// Put a pointer to __asan_set_seh_filter at the end of the global list
143// of C initializers, after the default EH is set by the CRT.
144#pragma section(".CRT$XIZ", long, read)  // NOLINT
145static __declspec(allocate(".CRT$XIZ"))
146    int (*__intercept_seh)() = __asan_set_seh_filter;
147#endif
148
149}  // namespace __asan
150
151#endif  // _WIN32
152