asan_win.cc revision 8a5d8c4d2826830b8a5bbce207145fc5436119a5
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 // InterlockedExchange16 seems unavailable on some MSVS installations. 239 // Everybody stand back, I pretend to know inline assembly! 240 // FIXME: I assume VC is smart enough to save/restore eax/ecx? 241 __asm { 242 mov eax, a 243 mov cx, new_val 244 xchg [eax], cx 245 mov new_val, cx 246 } 247 return new_val; 248} 249 250const char* AsanGetEnv(const char* name) { 251 static char env_buffer[32767] = {}; 252 253 // Note: this implementation stores the result in a static buffer so we only 254 // allow it to be called just once. 255 static bool called_once = false; 256 if (called_once) 257 UNIMPLEMENTED(); 258 called_once = true; 259 260 DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer)); 261 if (rv > 0 && rv < sizeof(env_buffer)) 262 return env_buffer; 263 return NULL; 264} 265 266void AsanDumpProcessMap() { 267 UNIMPLEMENTED(); 268} 269 270int GetPid() { 271 return GetProcessId(GetCurrentProcess()); 272} 273 274uintptr_t GetThreadSelf() { 275 return GetCurrentThreadId(); 276} 277 278void SetAlternateSignalStack() { 279 // FIXME: Decide what to do on Windows. 280} 281 282void UnsetAlternateSignalStack() { 283 // FIXME: Decide what to do on Windows. 284} 285 286void InstallSignalHandlers() { 287 // FIXME: Decide what to do on Windows. 288} 289 290void AsanDisableCoreDumper() { 291 UNIMPLEMENTED(); 292} 293 294void SleepForSeconds(int seconds) { 295 Sleep(seconds * 1000); 296} 297 298void Exit(int exitcode) { 299 _exit(exitcode); 300} 301 302int Atexit(void (*function)(void)) { 303 return atexit(function); 304} 305 306void SortArray(uintptr_t *array, size_t size) { 307 std::sort(array, array + size); 308} 309 310} // namespace __asan 311 312#endif // _WIN32 313