asan_win.cc revision f1e82b8fda94535e9a646fc5fe394d9883ccfa2c
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(uintptr_t fixed_addr, size_t size) { 36 return VirtualAlloc((LPVOID)fixed_addr, size, 37 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 38} 39 40void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { 41 void *rv = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 42 if (rv == NULL) 43 OutOfMemoryMessageAndDie(mem_type, size); 44 return rv; 45} 46 47void *AsanMprotect(uintptr_t fixed_addr, size_t size) { 48 return VirtualAlloc((LPVOID)fixed_addr, size, 49 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 50} 51 52void AsanUnmapOrDie(void *addr, size_t size) { 53 CHECK(VirtualFree(addr, size, MEM_DECOMMIT)); 54} 55 56// ---------------------- IO ---------------- {{{1 57size_t AsanWrite(int fd, const void *buf, size_t count) { 58 if (fd != 2) 59 UNIMPLEMENTED(); 60 61 HANDLE err = GetStdHandle(STD_ERROR_HANDLE); 62 if (err == NULL) 63 return 0; // FIXME: this might not work on some apps. 64 DWORD ret; 65 if (!WriteFile(err, buf, count, &ret, NULL)) 66 return 0; 67 return ret; 68} 69 70// FIXME: Looks like these functions are not needed and are linked in by the 71// code unreachable on Windows. We should clean this up. 72int AsanOpenReadonly(const char* filename) { 73 UNIMPLEMENTED(); 74} 75 76size_t AsanRead(int fd, void *buf, size_t count) { 77 UNIMPLEMENTED(); 78} 79 80int AsanClose(int fd) { 81 UNIMPLEMENTED(); 82} 83 84// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 85static AsanLock dbghelp_lock(LINKER_INITIALIZED); 86static bool dbghelp_initialized = false; 87#pragma comment(lib, "dbghelp.lib") 88 89void AsanThread::SetThreadStackTopAndBottom() { 90 MEMORY_BASIC_INFORMATION mbi; 91 CHECK(VirtualQuery(&mbi /* on stack */, 92 &mbi, sizeof(mbi)) != 0); 93 // FIXME: is it possible for the stack to not be a single allocation? 94 // Are these values what ASan expects to get (reserved, not committed; 95 // including stack guard page) ? 96 stack_top_ = (uintptr_t)mbi.BaseAddress + mbi.RegionSize; 97 stack_bottom_ = (uintptr_t)mbi.AllocationBase; 98} 99 100void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) { 101 max_size = max_s; 102 void *tmp[kStackTraceMax]; 103 104 // FIXME: CaptureStackBackTrace might be too slow for us. 105 // FIXME: Compare with StackWalk64. 106 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 107 size_t cs_ret = CaptureStackBackTrace(1, max_size, tmp, NULL), 108 offset = 0; 109 // Skip the RTL frames by searching for the PC in the stacktrace. 110 // FIXME: this doesn't work well for the malloc/free stacks yet. 111 for (size_t i = 0; i < cs_ret; i++) { 112 if (pc != (uintptr_t)tmp[i]) 113 continue; 114 offset = i; 115 break; 116 } 117 118 size = cs_ret - offset; 119 for (size_t i = 0; i < size; i++) 120 trace[i] = (uintptr_t)tmp[i + offset]; 121} 122 123bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 124 ScopedLock lock(&dbghelp_lock); 125 if (!dbghelp_initialized) { 126 SymSetOptions(SYMOPT_DEFERRED_LOADS | 127 SYMOPT_UNDNAME | 128 SYMOPT_LOAD_LINES); 129 CHECK(SymInitialize(GetCurrentProcess(), NULL, TRUE)); 130 // FIXME: We don't call SymCleanup() on exit yet - should we? 131 dbghelp_initialized = true; 132 } 133 134 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 135 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 136 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 137 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 138 symbol->MaxNameLen = MAX_SYM_NAME; 139 DWORD64 offset = 0; 140 BOOL got_objname = SymFromAddr(GetCurrentProcess(), 141 (DWORD64)addr, &offset, symbol); 142 if (!got_objname) 143 return false; 144 145 DWORD unused; 146 IMAGEHLP_LINE64 info; 147 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 148 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 149 (DWORD64)addr, &unused, &info); 150 int written = 0; 151 out_buffer[0] = '\0'; 152 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 153 if (got_fileline) { 154 written += SNPrintf(out_buffer + written, buffer_size - written, 155 " %s %s:%d", symbol->Name, 156 info.FileName, info.LineNumber); 157 } else { 158 written += SNPrintf(out_buffer + written, buffer_size - written, 159 " %s+0x%p", symbol->Name, offset); 160 } 161 return true; 162} 163 164// ---------------------- AsanLock ---------------- {{{1 165enum LockState { 166 LOCK_UNINITIALIZED = 0, 167 LOCK_READY = -1, 168}; 169 170AsanLock::AsanLock(LinkerInitialized li) { 171 // FIXME: see comments in AsanLock::Lock() for the details. 172 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 173 174 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 175 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 176 owner_ = LOCK_READY; 177} 178 179void AsanLock::Lock() { 180 if (owner_ == LOCK_UNINITIALIZED) { 181 // FIXME: hm, global AsanLock objects are not initialized?!? 182 // This might be a side effect of the clang+cl+link Frankenbuild... 183 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 184 185 // FIXME: If it turns out the linker doesn't invoke our 186 // constructors, we should probably manually Lock/Unlock all the global 187 // locks while we're starting in one thread to avoid double-init races. 188 } 189 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 190 CHECK(owner_ == LOCK_READY); 191 owner_ = GetThreadSelf(); 192} 193 194void AsanLock::Unlock() { 195 CHECK(owner_ == GetThreadSelf()); 196 owner_ = LOCK_READY; 197 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 198} 199 200// ---------------------- TSD ---------------- {{{1 201static bool tsd_key_inited = false; 202 203static __declspec(thread) void *fake_tsd = NULL; 204 205void AsanTSDInit(void (*destructor)(void *tsd)) { 206 // FIXME: we're ignoring the destructor for now. 207 tsd_key_inited = true; 208} 209 210void *AsanTSDGet() { 211 CHECK(tsd_key_inited); 212 return fake_tsd; 213} 214 215void AsanTSDSet(void *tsd) { 216 CHECK(tsd_key_inited); 217 fake_tsd = tsd; 218} 219 220// ---------------------- Various stuff ---------------- {{{1 221void *AsanDoesNotSupportStaticLinkage() { 222#if defined(_DEBUG) 223#error Please build the runtime with a non-debug CRT: /MD or /MT 224#endif 225 return NULL; 226} 227 228bool AsanShadowRangeIsAvailable() { 229 // FIXME: shall we do anything here on Windows? 230 return true; 231} 232 233int AtomicInc(int *a) { 234 return InterlockedExchangeAdd((LONG*)a, 1) + 1; 235} 236 237uint16_t AtomicExchange(uint16_t *a, uint16_t new_val) { 238 return InterlockedExchange16(a, new_val); 239} 240 241const char* AsanGetEnv(const char* name) { 242 static char env_buffer[32767] = {}; 243 244 // Note: this implementation stores the result in a static buffer so we only 245 // allow it to be called just once. 246 static bool called_once = false; 247 if (called_once) 248 UNIMPLEMENTED(); 249 called_once = true; 250 251 DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer)); 252 if (rv > 0 && rv < sizeof(env_buffer)) 253 return env_buffer; 254 return NULL; 255} 256 257void AsanDumpProcessMap() { 258 UNIMPLEMENTED(); 259} 260 261int GetPid() { 262 return GetProcessId(GetCurrentProcess()); 263} 264 265uintptr_t GetThreadSelf() { 266 return GetCurrentThreadId(); 267} 268 269void SetAlternateSignalStack() { 270 // FIXME: Decide what to do on Windows. 271} 272 273void UnsetAlternateSignalStack() { 274 // FIXME: Decide what to do on Windows. 275} 276 277void InstallSignalHandlers() { 278 // FIXME: Decide what to do on Windows. 279} 280 281void AsanDisableCoreDumper() { 282 UNIMPLEMENTED(); 283} 284 285void SleepForSeconds(int seconds) { 286 Sleep(seconds * 1000); 287} 288 289void Exit(int exitcode) { 290 _exit(exitcode); 291} 292 293int Atexit(void (*function)(void)) { 294 return atexit(function); 295} 296 297void SortArray(uintptr_t *array, size_t size) { 298 std::sort(array, array + size); 299} 300 301} // namespace __asan 302 303#endif // _WIN32 304