asan_win.cc revision 7ebac9534c484b06a0c2822d83f082a127e743bc
1//===-- asan_win.cc -------------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of AddressSanitizer, an address sanity checker. 11// 12// Windows-specific details. 13//===----------------------------------------------------------------------===// 14#ifdef _WIN32 15#include <windows.h> 16 17#include <dbghelp.h> 18#include <stdlib.h> 19 20#include <new> // FIXME: temporarily needed for placement new in AsanLock. 21 22#include "asan_interceptors.h" 23#include "asan_internal.h" 24#include "asan_lock.h" 25#include "asan_procmaps.h" 26#include "asan_thread.h" 27 28// Should not add dependency on libstdc++, 29// since most of the stuff here is inlinable. 30#include <algorithm> 31 32namespace __asan { 33 34// ---------------------- Memory management ---------------- {{{1 35void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) { 36 return VirtualAlloc((LPVOID)fixed_addr, size, 37 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 38} 39 40void *AsanMmapSomewhereOrDie(uptr size, const char *mem_type) { 41 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 42 if (rv == 0) 43 OutOfMemoryMessageAndDie(mem_type, size); 44 return rv; 45} 46 47void *AsanMprotect(uptr fixed_addr, uptr size) { 48 return VirtualAlloc((LPVOID)fixed_addr, size, 49 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 50} 51 52void AsanUnmapOrDie(void *addr, uptr size) { 53 CHECK(VirtualFree(addr, size, MEM_DECOMMIT)); 54} 55 56// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 57static AsanLock dbghelp_lock(LINKER_INITIALIZED); 58static bool dbghelp_initialized = false; 59#pragma comment(lib, "dbghelp.lib") 60 61void AsanThread::SetThreadStackTopAndBottom() { 62 MEMORY_BASIC_INFORMATION mbi; 63 CHECK(VirtualQuery(&mbi /* on stack */, 64 &mbi, sizeof(mbi)) != 0); 65 // FIXME: is it possible for the stack to not be a single allocation? 66 // Are these values what ASan expects to get (reserved, not committed; 67 // including stack guard page) ? 68 stack_top_ = (uptr)mbi.BaseAddress + mbi.RegionSize; 69 stack_bottom_ = (uptr)mbi.AllocationBase; 70} 71 72void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 73 max_size = max_s; 74 void *tmp[kStackTraceMax]; 75 76 // FIXME: CaptureStackBackTrace might be too slow for us. 77 // FIXME: Compare with StackWalk64. 78 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 79 uptr cs_ret = CaptureStackBackTrace(1, max_size, tmp, 0), 80 offset = 0; 81 // Skip the RTL frames by searching for the PC in the stacktrace. 82 // FIXME: this doesn't work well for the malloc/free stacks yet. 83 for (uptr i = 0; i < cs_ret; i++) { 84 if (pc != (uptr)tmp[i]) 85 continue; 86 offset = i; 87 break; 88 } 89 90 size = cs_ret - offset; 91 for (uptr i = 0; i < size; i++) 92 trace[i] = (uptr)tmp[i + offset]; 93} 94 95bool __asan_WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 96 ScopedLock lock(&dbghelp_lock); 97 if (!dbghelp_initialized) { 98 SymSetOptions(SYMOPT_DEFERRED_LOADS | 99 SYMOPT_UNDNAME | 100 SYMOPT_LOAD_LINES); 101 CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE)); 102 // FIXME: We don't call SymCleanup() on exit yet - should we? 103 dbghelp_initialized = true; 104 } 105 106 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 107 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 108 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 109 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 110 symbol->MaxNameLen = MAX_SYM_NAME; 111 DWORD64 offset = 0; 112 BOOL got_objname = SymFromAddr(GetCurrentProcess(), 113 (DWORD64)addr, &offset, symbol); 114 if (!got_objname) 115 return false; 116 117 DWORD unused; 118 IMAGEHLP_LINE64 info; 119 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 120 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 121 (DWORD64)addr, &unused, &info); 122 int written = 0; 123 out_buffer[0] = '\0'; 124 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 125 if (got_fileline) { 126 written += SNPrintf(out_buffer + written, buffer_size - written, 127 " %s %s:%d", symbol->Name, 128 info.FileName, info.LineNumber); 129 } else { 130 written += SNPrintf(out_buffer + written, buffer_size - written, 131 " %s+0x%p", symbol->Name, offset); 132 } 133 return true; 134} 135 136// ---------------------- AsanLock ---------------- {{{1 137enum LockState { 138 LOCK_UNINITIALIZED = 0, 139 LOCK_READY = -1, 140}; 141 142AsanLock::AsanLock(LinkerInitialized li) { 143 // FIXME: see comments in AsanLock::Lock() for the details. 144 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 145 146 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 147 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 148 owner_ = LOCK_READY; 149} 150 151void AsanLock::Lock() { 152 if (owner_ == LOCK_UNINITIALIZED) { 153 // FIXME: hm, global AsanLock objects are not initialized?!? 154 // This might be a side effect of the clang+cl+link Frankenbuild... 155 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 156 157 // FIXME: If it turns out the linker doesn't invoke our 158 // constructors, we should probably manually Lock/Unlock all the global 159 // locks while we're starting in one thread to avoid double-init races. 160 } 161 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 162 CHECK(owner_ == LOCK_READY); 163 owner_ = GetThreadSelf(); 164} 165 166void AsanLock::Unlock() { 167 CHECK(owner_ == GetThreadSelf()); 168 owner_ = LOCK_READY; 169 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 170} 171 172// ---------------------- TSD ---------------- {{{1 173static bool tsd_key_inited = false; 174 175static __declspec(thread) void *fake_tsd = 0; 176 177void AsanTSDInit(void (*destructor)(void *tsd)) { 178 // FIXME: we're ignoring the destructor for now. 179 tsd_key_inited = true; 180} 181 182void *AsanTSDGet() { 183 CHECK(tsd_key_inited); 184 return fake_tsd; 185} 186 187void AsanTSDSet(void *tsd) { 188 CHECK(tsd_key_inited); 189 fake_tsd = tsd; 190} 191 192// ---------------------- Various stuff ---------------- {{{1 193void *AsanDoesNotSupportStaticLinkage() { 194#if defined(_DEBUG) 195#error Please build the runtime with a non-debug CRT: /MD or /MT 196#endif 197 return 0; 198} 199 200bool AsanShadowRangeIsAvailable() { 201 // FIXME: shall we do anything here on Windows? 202 return true; 203} 204 205int AtomicInc(int *a) { 206 return InterlockedExchangeAdd((LONG*)a, 1) + 1; 207} 208 209u16 AtomicExchange(u16 *a, u16 new_val) { 210 // InterlockedExchange16 seems unavailable on some MSVS installations. 211 // Everybody stand back, I pretend to know inline assembly! 212 // FIXME: I assume VC is smart enough to save/restore eax/ecx? 213 __asm { 214 mov eax, a 215 mov cx, new_val 216 xchg [eax], cx ; NOLINT 217 mov new_val, cx 218 } 219 return new_val; 220} 221 222u16 AtomicExchange(u16 *a, u16 new_val) { 223 // FIXME: can we do this with a proper xchg intrinsic? 224 u8 t = *a; 225 *a = new_val; 226 return t; 227} 228 229const char* AsanGetEnv(const char* name) { 230 static char env_buffer[32767] = {}; 231 232 // Note: this implementation stores the result in a static buffer so we only 233 // allow it to be called just once. 234 static bool called_once = false; 235 if (called_once) 236 UNIMPLEMENTED(); 237 called_once = true; 238 239 DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer)); 240 if (rv > 0 && rv < sizeof(env_buffer)) 241 return env_buffer; 242 return 0; 243} 244 245void AsanDumpProcessMap() { 246 UNIMPLEMENTED(); 247} 248 249uptr GetThreadSelf() { 250 return GetCurrentThreadId(); 251} 252 253void SetAlternateSignalStack() { 254 // FIXME: Decide what to do on Windows. 255} 256 257void UnsetAlternateSignalStack() { 258 // FIXME: Decide what to do on Windows. 259} 260 261void InstallSignalHandlers() { 262 // FIXME: Decide what to do on Windows. 263} 264 265void AsanDisableCoreDumper() { 266 UNIMPLEMENTED(); 267} 268 269void SleepForSeconds(int seconds) { 270 Sleep(seconds * 1000); 271} 272 273void Exit(int exitcode) { 274 _exit(exitcode); 275} 276 277void Abort() { 278 abort(); 279 _exit(-1); // abort is not NORETURN on Windows. 280} 281 282int Atexit(void (*function)(void)) { 283 return atexit(function); 284} 285 286void SortArray(uptr *array, uptr size) { 287 std::sort(array, array + size); 288} 289 290} // namespace __asan 291 292#endif // _WIN32 293