sanitizer_win.cc revision 5a58ef4284194419446d77037441f92d85ab7e4c
1//===-- sanitizer_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 shared between AddressSanitizer and ThreadSanitizer 11// run-time libraries and implements windows-specific functions from 12// sanitizer_libc.h. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_platform.h" 16#if SANITIZER_WINDOWS 17 18#define WIN32_LEAN_AND_MEAN 19#define NOGDI 20#include <stdlib.h> 21#include <io.h> 22#include <windows.h> 23 24#include "sanitizer_common.h" 25#include "sanitizer_libc.h" 26#include "sanitizer_mutex.h" 27#include "sanitizer_placement_new.h" 28#include "sanitizer_stacktrace.h" 29 30namespace __sanitizer { 31 32#include "sanitizer_syscall_generic.inc" 33 34// --------------------- sanitizer_common.h 35uptr GetPageSize() { 36 return 1U << 14; // FIXME: is this configurable? 37} 38 39uptr GetMmapGranularity() { 40 return 1U << 16; // FIXME: is this configurable? 41} 42 43uptr GetMaxVirtualAddress() { 44 SYSTEM_INFO si; 45 GetSystemInfo(&si); 46 return (uptr)si.lpMaximumApplicationAddress; 47} 48 49bool FileExists(const char *filename) { 50 UNIMPLEMENTED(); 51} 52 53uptr internal_getpid() { 54 return GetProcessId(GetCurrentProcess()); 55} 56 57// In contrast to POSIX, on Windows GetCurrentThreadId() 58// returns a system-unique identifier. 59uptr GetTid() { 60 return GetCurrentThreadId(); 61} 62 63uptr GetThreadSelf() { 64 return GetTid(); 65} 66 67void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 68 uptr *stack_bottom) { 69 CHECK(stack_top); 70 CHECK(stack_bottom); 71 MEMORY_BASIC_INFORMATION mbi; 72 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); 73 // FIXME: is it possible for the stack to not be a single allocation? 74 // Are these values what ASan expects to get (reserved, not committed; 75 // including stack guard page) ? 76 *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; 77 *stack_bottom = (uptr)mbi.AllocationBase; 78} 79 80void *MmapOrDie(uptr size, const char *mem_type) { 81 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 82 if (rv == 0) { 83 Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n", 84 size, size, mem_type); 85 CHECK("unable to mmap" && 0); 86 } 87 return rv; 88} 89 90void UnmapOrDie(void *addr, uptr size) { 91 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 92 Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n", 93 size, size, addr); 94 CHECK("unable to unmap" && 0); 95 } 96} 97 98void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 99 // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 100 // but on Win64 it does. 101 void *p = VirtualAlloc((LPVOID)fixed_addr, size, 102 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 103 if (p == 0) 104 Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n", 105 size, size, fixed_addr, GetLastError()); 106 return p; 107} 108 109void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 110 return MmapFixedNoReserve(fixed_addr, size); 111} 112 113void *Mprotect(uptr fixed_addr, uptr size) { 114 return VirtualAlloc((LPVOID)fixed_addr, size, 115 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 116} 117 118void FlushUnneededShadowMemory(uptr addr, uptr size) { 119 // This is almost useless on 32-bits. 120 // FIXME: add madvice-analog when we move to 64-bits. 121} 122 123bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 124 // FIXME: shall we do anything here on Windows? 125 return true; 126} 127 128void *MapFileToMemory(const char *file_name, uptr *buff_size) { 129 UNIMPLEMENTED(); 130} 131 132static const int kMaxEnvNameLength = 128; 133static const DWORD kMaxEnvValueLength = 32767; 134 135namespace { 136 137struct EnvVariable { 138 char name[kMaxEnvNameLength]; 139 char value[kMaxEnvValueLength]; 140}; 141 142} // namespace 143 144static const int kEnvVariables = 5; 145static EnvVariable env_vars[kEnvVariables]; 146static int num_env_vars; 147 148const char *GetEnv(const char *name) { 149 // Note: this implementation caches the values of the environment variables 150 // and limits their quantity. 151 for (int i = 0; i < num_env_vars; i++) { 152 if (0 == internal_strcmp(name, env_vars[i].name)) 153 return env_vars[i].value; 154 } 155 CHECK_LT(num_env_vars, kEnvVariables); 156 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 157 kMaxEnvValueLength); 158 if (rv > 0 && rv < kMaxEnvValueLength) { 159 CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 160 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 161 num_env_vars++; 162 return env_vars[num_env_vars - 1].value; 163 } 164 return 0; 165} 166 167const char *GetPwd() { 168 UNIMPLEMENTED(); 169} 170 171u32 GetUid() { 172 UNIMPLEMENTED(); 173} 174 175void DumpProcessMap() { 176 UNIMPLEMENTED(); 177} 178 179void DisableCoreDumper() { 180 UNIMPLEMENTED(); 181} 182 183void ReExec() { 184 UNIMPLEMENTED(); 185} 186 187void PrepareForSandboxing() { 188 // Nothing here for now. 189} 190 191bool StackSizeIsUnlimited() { 192 UNIMPLEMENTED(); 193} 194 195void SetStackSizeLimitInBytes(uptr limit) { 196 UNIMPLEMENTED(); 197} 198 199char *FindPathToBinary(const char *name) { 200 // Nothing here for now. 201 return 0; 202} 203 204void SleepForSeconds(int seconds) { 205 Sleep(seconds * 1000); 206} 207 208void SleepForMillis(int millis) { 209 Sleep(millis); 210} 211 212u64 NanoTime() { 213 return 0; 214} 215 216void Abort() { 217 abort(); 218 _exit(-1); // abort is not NORETURN on Windows. 219} 220 221#ifndef SANITIZER_GO 222int Atexit(void (*function)(void)) { 223 return atexit(function); 224} 225#endif 226 227// ------------------ sanitizer_libc.h 228uptr internal_mmap(void *addr, uptr length, int prot, int flags, 229 int fd, u64 offset) { 230 UNIMPLEMENTED(); 231} 232 233uptr internal_munmap(void *addr, uptr length) { 234 UNIMPLEMENTED(); 235} 236 237uptr internal_close(fd_t fd) { 238 UNIMPLEMENTED(); 239} 240 241int internal_isatty(fd_t fd) { 242 return _isatty(fd); 243} 244 245uptr internal_open(const char *filename, int flags) { 246 UNIMPLEMENTED(); 247} 248 249uptr internal_open(const char *filename, int flags, u32 mode) { 250 UNIMPLEMENTED(); 251} 252 253uptr OpenFile(const char *filename, bool write) { 254 UNIMPLEMENTED(); 255} 256 257uptr internal_read(fd_t fd, void *buf, uptr count) { 258 UNIMPLEMENTED(); 259} 260 261uptr internal_write(fd_t fd, const void *buf, uptr count) { 262 if (fd != kStderrFd) 263 UNIMPLEMENTED(); 264 HANDLE err = GetStdHandle(STD_ERROR_HANDLE); 265 if (err == 0) 266 return 0; // FIXME: this might not work on some apps. 267 DWORD ret; 268 if (!WriteFile(err, buf, count, &ret, 0)) 269 return 0; 270 return ret; 271} 272 273uptr internal_stat(const char *path, void *buf) { 274 UNIMPLEMENTED(); 275} 276 277uptr internal_lstat(const char *path, void *buf) { 278 UNIMPLEMENTED(); 279} 280 281uptr internal_fstat(fd_t fd, void *buf) { 282 UNIMPLEMENTED(); 283} 284 285uptr internal_filesize(fd_t fd) { 286 UNIMPLEMENTED(); 287} 288 289uptr internal_dup2(int oldfd, int newfd) { 290 UNIMPLEMENTED(); 291} 292 293uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 294 UNIMPLEMENTED(); 295} 296 297uptr internal_sched_yield() { 298 Sleep(0); 299 return 0; 300} 301 302void internal__exit(int exitcode) { 303 _exit(exitcode); 304} 305 306// ---------------------- BlockingMutex ---------------- {{{1 307const uptr LOCK_UNINITIALIZED = 0; 308const uptr LOCK_READY = (uptr)-1; 309 310BlockingMutex::BlockingMutex(LinkerInitialized li) { 311 // FIXME: see comments in BlockingMutex::Lock() for the details. 312 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 313 314 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 315 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 316 owner_ = LOCK_READY; 317} 318 319BlockingMutex::BlockingMutex() { 320 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 321 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 322 owner_ = LOCK_READY; 323} 324 325void BlockingMutex::Lock() { 326 if (owner_ == LOCK_UNINITIALIZED) { 327 // FIXME: hm, global BlockingMutex objects are not initialized?!? 328 // This might be a side effect of the clang+cl+link Frankenbuild... 329 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); 330 331 // FIXME: If it turns out the linker doesn't invoke our 332 // constructors, we should probably manually Lock/Unlock all the global 333 // locks while we're starting in one thread to avoid double-init races. 334 } 335 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 336 CHECK_EQ(owner_, LOCK_READY); 337 owner_ = GetThreadSelf(); 338} 339 340void BlockingMutex::Unlock() { 341 CHECK_EQ(owner_, GetThreadSelf()); 342 owner_ = LOCK_READY; 343 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 344} 345 346void BlockingMutex::CheckLocked() { 347 CHECK_EQ(owner_, GetThreadSelf()); 348} 349 350uptr GetTlsSize() { 351 return 0; 352} 353 354void InitTlsSize() { 355} 356 357void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 358 uptr *tls_addr, uptr *tls_size) { 359#ifdef SANITIZER_GO 360 *stk_addr = 0; 361 *stk_size = 0; 362 *tls_addr = 0; 363 *tls_size = 0; 364#else 365 uptr stack_top, stack_bottom; 366 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 367 *stk_addr = stack_bottom; 368 *stk_size = stack_top - stack_bottom; 369 *tls_addr = 0; 370 *tls_size = 0; 371#endif 372} 373 374void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, 375 uptr stack_top, uptr stack_bottom, bool fast) { 376 (void)fast; 377 (void)stack_top; 378 (void)stack_bottom; 379 stack->max_size = max_s; 380 void *tmp[kStackTraceMax]; 381 382 // FIXME: CaptureStackBackTrace might be too slow for us. 383 // FIXME: Compare with StackWalk64. 384 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 385 uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0); 386 uptr offset = 0; 387 // Skip the RTL frames by searching for the PC in the stacktrace. 388 // FIXME: this doesn't work well for the malloc/free stacks yet. 389 for (uptr i = 0; i < cs_ret; i++) { 390 if (pc != (uptr)tmp[i]) 391 continue; 392 offset = i; 393 break; 394 } 395 396 stack->size = cs_ret - offset; 397 for (uptr i = 0; i < stack->size; i++) 398 stack->trace[i] = (uptr)tmp[i + offset]; 399} 400 401} // namespace __sanitizer 402 403#endif // _WIN32 404