asan_win.cc revision fa3daaf1d66314658e7c05bf63dc825d179f2faf
11aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca//===-- asan_win.cc -------------------------------------------------------===// 21aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// 31aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// The LLVM Compiler Infrastructure 41aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// 51aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// This file is distributed under the University of Illinois Open Source 61aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// License. See LICENSE.TXT for details. 71aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// 81aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca//===----------------------------------------------------------------------===// 91aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// 101aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// This file is a part of AddressSanitizer, an address sanity checker. 111aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// 121aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// Windows-specific details. 131aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca//===----------------------------------------------------------------------===// 141aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#ifdef _WIN32 151aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include <windows.h> 161aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 171aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include <dbghelp.h> 181aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include <stdlib.h> 191aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 201aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include <new> // FIXME: temporarily needed for placement new in AsanLock. 211aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 221aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include "asan_interceptors.h" 231aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include "asan_internal.h" 241aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include "asan_lock.h" 251aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#include "asan_thread.h" 261aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 271aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// Should not add dependency on libstdc++, 285811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonseca// since most of the stuff here is inlinable. 295811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonseca#include <algorithm> 305811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonseca 315811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonsecanamespace __asan { 325811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonseca 335811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonseca// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 345811ed87d732101ab8cfbd087bc99d8c6c963f30José Fonsecastatic AsanLock dbghelp_lock(LINKER_INITIALIZED); 351aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecastatic bool dbghelp_initialized = false; 367cda8ea44c2b65265cefa79bd29a4990ac81cee6José Fonseca#pragma comment(lib, "dbghelp.lib") 3788b6abfba5e95866877dd3939ae43c6dfd71422cJosé Fonseca 38854627387db5c1bf3f69d56a638fab2af0c46010José Fonsecavoid AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 397cda8ea44c2b65265cefa79bd29a4990ac81cee6José Fonseca max_size = max_s; 401aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca void *tmp[kStackTraceMax]; 4109a7b011acb3957725bb7e1bc4125f0939a295e7José Fonseca 42efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul // FIXME: CaptureStackBackTrace might be too slow for us. 431aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // FIXME: Compare with StackWalk64. 44dcc5d7f67220bc93aa7a351658649877c7e4cf69José Fonseca // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 451aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca uptr cs_ret = CaptureStackBackTrace(1, max_size, tmp, 0), 461aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca offset = 0; 471aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // Skip the RTL frames by searching for the PC in the stacktrace. 48a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca // FIXME: this doesn't work well for the malloc/free stacks yet. 49a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca for (uptr i = 0; i < cs_ret; i++) { 50a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca if (pc != (uptr)tmp[i]) 51a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca continue; 52a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca offset = i; 53a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca break; 54a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca } 553469715a8a171512cf9b528702e70393f01c6041José Fonseca 563469715a8a171512cf9b528702e70393f01c6041José Fonseca size = cs_ret - offset; 57a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca for (uptr i = 0; i < size; i++) 58a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca trace[i] = (uptr)tmp[i + offset]; 59a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca} 60a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca 61a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonsecabool __asan_WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 62a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca ScopedLock lock(&dbghelp_lock); 63a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca if (!dbghelp_initialized) { 64a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca SymSetOptions(SYMOPT_DEFERRED_LOADS | 65a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca SYMOPT_UNDNAME | 66a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca SYMOPT_LOAD_LINES); 67a75519cb43c85b99cd54bc46dd83accda0cbd6cdJosé Fonseca CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE)); 68e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul // FIXME: We don't call SymCleanup() on exit yet - should we? 692297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul dbghelp_initialized = true; 702297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul } 71877f2356b2ab7caa16beed496f36eca64ee201e1Brian Paul 72e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 731aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 74efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 752297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 762297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul symbol->MaxNameLen = MAX_SYM_NAME; 772297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul DWORD64 offset = 0; 782297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul BOOL got_objname = SymFromAddr(GetCurrentProcess(), 791aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca (DWORD64)addr, &offset, symbol); 80efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul if (!got_objname) 81efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul return false; 821aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 831aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca DWORD unused; 841aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca IMAGEHLP_LINE64 info; 85241c3a1d8001fc5a30e2af4b4636b48e6f99690aJosé Fonseca info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 861aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 87e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul (DWORD64)addr, &unused, &info); 88e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul int written = 0; 89a44a6960fab8c0053678fe74ce4c978ef40b06ffnobled out_buffer[0] = '\0'; 90a44a6960fab8c0053678fe74ce4c978ef40b06ffnobled // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 91e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul if (got_fileline) { 921aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca written += SNPrintf(out_buffer + written, buffer_size - written, 931aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca " %s %s:%d", symbol->Name, 941aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca info.FileName, info.LineNumber); 951aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca } else { 961aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca written += SNPrintf(out_buffer + written, buffer_size - written, 976b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca " %s+0x%p", symbol->Name, offset); 986b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca } 996b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca return true; 1006b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca} 1011aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1026b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca// ---------------------- AsanLock ---------------- {{{1 1036b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonsecaenum LockState { 1046b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca LOCK_UNINITIALIZED = 0, 1056b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca LOCK_READY = -1, 1066b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca}; 1076b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca 1086b0c79e058d4d008cad32c0ff06de9757ccd6fa0José FonsecaAsanLock::AsanLock(LinkerInitialized li) { 1096b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca // FIXME: see comments in AsanLock::Lock() for the details. 1106b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 1116b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca 1126b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 1136b0c79e058d4d008cad32c0ff06de9757ccd6fa0José Fonseca InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 1141aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca owner_ = LOCK_READY; 115489af2a3ba467e4341cb8504a0e59cf5828864d4Brian Paul} 1161aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1171aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid AsanLock::Lock() { 1187cda8ea44c2b65265cefa79bd29a4990ac81cee6José Fonseca if (owner_ == LOCK_UNINITIALIZED) { 119e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul // FIXME: hm, global AsanLock objects are not initialized?!? 120efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul // This might be a side effect of the clang+cl+link Frankenbuild... 1211aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 1221aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1231aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // FIXME: If it turns out the linker doesn't invoke our 1241aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // constructors, we should probably manually Lock/Unlock all the global 1251aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // locks while we're starting in one thread to avoid double-init races. 1261aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca } 1271aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 1281aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca CHECK(owner_ == LOCK_READY); 1291aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca owner_ = GetThreadSelf(); 1301aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1311aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1321aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid AsanLock::Unlock() { 1331aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca CHECK(owner_ == GetThreadSelf()); 1341aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca owner_ = LOCK_READY; 1351aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 1361aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1371aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1381aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// ---------------------- TSD ---------------- {{{1 1391aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecastatic bool tsd_key_inited = false; 1401aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1411aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecastatic __declspec(thread) void *fake_tsd = 0; 1421aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1431aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid AsanTSDInit(void (*destructor)(void *tsd)) { 1441aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // FIXME: we're ignoring the destructor for now. 1451aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca tsd_key_inited = true; 1461aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1471aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1481aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid *AsanTSDGet() { 149efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul CHECK(tsd_key_inited); 1501aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca return fake_tsd; 1511aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1521aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1531aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid AsanTSDSet(void *tsd) { 1541aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca CHECK(tsd_key_inited); 1551aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca fake_tsd = tsd; 1561aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1571aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1581aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca// ---------------------- Various stuff ---------------- {{{1 1591aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonsecavoid *AsanDoesNotSupportStaticLinkage() { 1601aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca#if defined(_DEBUG) 161efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul#error Please build the runtime with a non-debug CRT: /MD or /MT 1622297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paul#endif 1631aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca return 0; 1641aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca} 1651aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca 1662297bc9233be014b7b5aa037769209fbe9f6a66cBrian Paulbool AsanShadowRangeIsAvailable() { 1671aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca // FIXME: shall we do anything here on Windows? 1681aede69d3a8d288af11c2ef620b51e71c2ce89b2José Fonseca return true; 1697cda8ea44c2b65265cefa79bd29a4990ac81cee6José Fonseca} 170e01fa1eaec34675d0b30127de4f78b020a092a83Brian Paul 171d07b0383660cd318ba43abad11bb80de4a124951José Fonsecaint AtomicInc(int *a) { 172d07b0383660cd318ba43abad11bb80de4a124951José Fonseca return InterlockedExchangeAdd((LONG*)a, 1) + 1; 173d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 174d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 175d07b0383660cd318ba43abad11bb80de4a124951José Fonsecau16 AtomicExchange(u16 *a, u16 new_val) { 176d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // InterlockedExchange16 seems unavailable on some MSVS installations. 177d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // Everybody stand back, I pretend to know inline assembly! 178d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // FIXME: I assume VC is smart enough to save/restore eax/ecx? 179d07b0383660cd318ba43abad11bb80de4a124951José Fonseca __asm { 180d07b0383660cd318ba43abad11bb80de4a124951José Fonseca mov eax, a 181d07b0383660cd318ba43abad11bb80de4a124951José Fonseca mov cx, new_val 182d07b0383660cd318ba43abad11bb80de4a124951José Fonseca xchg [eax], cx ; NOLINT 183d07b0383660cd318ba43abad11bb80de4a124951José Fonseca mov new_val, cx 184d07b0383660cd318ba43abad11bb80de4a124951José Fonseca } 185d07b0383660cd318ba43abad11bb80de4a124951José Fonseca return new_val; 186d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 187d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 188d07b0383660cd318ba43abad11bb80de4a124951José Fonsecau8 AtomicExchange(u8 *a, u8 new_val) { 189d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // FIXME: can we do this with a proper xchg intrinsic? 190efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul u8 t = *a; 191d07b0383660cd318ba43abad11bb80de4a124951José Fonseca *a = new_val; 192d07b0383660cd318ba43abad11bb80de4a124951José Fonseca return t; 193d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 194d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 195d07b0383660cd318ba43abad11bb80de4a124951José Fonsecavoid SetAlternateSignalStack() { 196d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // FIXME: Decide what to do on Windows. 197d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 198d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 199d07b0383660cd318ba43abad11bb80de4a124951José Fonsecavoid UnsetAlternateSignalStack() { 200d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // FIXME: Decide what to do on Windows. 201d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 202d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 203d07b0383660cd318ba43abad11bb80de4a124951José Fonsecavoid InstallSignalHandlers() { 204d07b0383660cd318ba43abad11bb80de4a124951José Fonseca // FIXME: Decide what to do on Windows. 205d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 206d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 207efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paulvoid SortArray(uptr *array, uptr size) { 208d07b0383660cd318ba43abad11bb80de4a124951José Fonseca std::sort(array, array + size); 209d07b0383660cd318ba43abad11bb80de4a124951José Fonseca} 210b3d4e5bd26a44870af7d2413cca7a6f576a0984aJosé Fonseca 211b3d4e5bd26a44870af7d2413cca7a6f576a0984aJosé Fonseca} // namespace __asan 212d07b0383660cd318ba43abad11bb80de4a124951José Fonseca 213b3d4e5bd26a44870af7d2413cca7a6f576a0984aJosé Fonseca#endif // _WIN32 214efc82aef35a2aac5d2ed9774f6d28f2626796416Brian Paul