sanitizer_win.cc revision 7847d77b246635211c3bf465421d49d7af5226c1
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 221uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 222 string_predicate_t filter) { 223 UNIMPLEMENTED(); 224}; 225 226#ifndef SANITIZER_GO 227int Atexit(void (*function)(void)) { 228 return atexit(function); 229} 230#endif 231 232// ------------------ sanitizer_libc.h 233uptr internal_mmap(void *addr, uptr length, int prot, int flags, 234 int fd, u64 offset) { 235 UNIMPLEMENTED(); 236} 237 238uptr internal_munmap(void *addr, uptr length) { 239 UNIMPLEMENTED(); 240} 241 242uptr internal_close(fd_t fd) { 243 UNIMPLEMENTED(); 244} 245 246int internal_isatty(fd_t fd) { 247 return _isatty(fd); 248} 249 250uptr internal_open(const char *filename, int flags) { 251 UNIMPLEMENTED(); 252} 253 254uptr internal_open(const char *filename, int flags, u32 mode) { 255 UNIMPLEMENTED(); 256} 257 258uptr OpenFile(const char *filename, bool write) { 259 UNIMPLEMENTED(); 260} 261 262uptr internal_read(fd_t fd, void *buf, uptr count) { 263 UNIMPLEMENTED(); 264} 265 266uptr internal_write(fd_t fd, const void *buf, uptr count) { 267 if (fd != kStderrFd) 268 UNIMPLEMENTED(); 269 HANDLE err = GetStdHandle(STD_ERROR_HANDLE); 270 if (err == 0) 271 return 0; // FIXME: this might not work on some apps. 272 DWORD ret; 273 if (!WriteFile(err, buf, count, &ret, 0)) 274 return 0; 275 return ret; 276} 277 278uptr internal_stat(const char *path, void *buf) { 279 UNIMPLEMENTED(); 280} 281 282uptr internal_lstat(const char *path, void *buf) { 283 UNIMPLEMENTED(); 284} 285 286uptr internal_fstat(fd_t fd, void *buf) { 287 UNIMPLEMENTED(); 288} 289 290uptr internal_filesize(fd_t fd) { 291 UNIMPLEMENTED(); 292} 293 294uptr internal_dup2(int oldfd, int newfd) { 295 UNIMPLEMENTED(); 296} 297 298uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 299 UNIMPLEMENTED(); 300} 301 302uptr internal_sched_yield() { 303 Sleep(0); 304 return 0; 305} 306 307void internal__exit(int exitcode) { 308 _exit(exitcode); 309} 310 311// ---------------------- BlockingMutex ---------------- {{{1 312const uptr LOCK_UNINITIALIZED = 0; 313const uptr LOCK_READY = (uptr)-1; 314 315BlockingMutex::BlockingMutex(LinkerInitialized li) { 316 // FIXME: see comments in BlockingMutex::Lock() for the details. 317 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 318 319 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 320 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 321 owner_ = LOCK_READY; 322} 323 324BlockingMutex::BlockingMutex() { 325 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 326 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 327 owner_ = LOCK_READY; 328} 329 330void BlockingMutex::Lock() { 331 if (owner_ == LOCK_UNINITIALIZED) { 332 // FIXME: hm, global BlockingMutex objects are not initialized?!? 333 // This might be a side effect of the clang+cl+link Frankenbuild... 334 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); 335 336 // FIXME: If it turns out the linker doesn't invoke our 337 // constructors, we should probably manually Lock/Unlock all the global 338 // locks while we're starting in one thread to avoid double-init races. 339 } 340 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 341 CHECK_EQ(owner_, LOCK_READY); 342 owner_ = GetThreadSelf(); 343} 344 345void BlockingMutex::Unlock() { 346 CHECK_EQ(owner_, GetThreadSelf()); 347 owner_ = LOCK_READY; 348 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 349} 350 351void BlockingMutex::CheckLocked() { 352 CHECK_EQ(owner_, GetThreadSelf()); 353} 354 355uptr GetTlsSize() { 356 return 0; 357} 358 359void InitTlsSize() { 360} 361 362void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 363 uptr *tls_addr, uptr *tls_size) { 364#ifdef SANITIZER_GO 365 *stk_addr = 0; 366 *stk_size = 0; 367 *tls_addr = 0; 368 *tls_size = 0; 369#else 370 uptr stack_top, stack_bottom; 371 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 372 *stk_addr = stack_bottom; 373 *stk_size = stack_top - stack_bottom; 374 *tls_addr = 0; 375 *tls_size = 0; 376#endif 377} 378 379void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, 380 uptr stack_top, uptr stack_bottom, bool fast) { 381 (void)fast; 382 (void)stack_top; 383 (void)stack_bottom; 384 stack->max_size = max_s; 385 void *tmp[kStackTraceMax]; 386 387 // FIXME: CaptureStackBackTrace might be too slow for us. 388 // FIXME: Compare with StackWalk64. 389 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 390 uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0); 391 uptr offset = 0; 392 // Skip the RTL frames by searching for the PC in the stacktrace. 393 // FIXME: this doesn't work well for the malloc/free stacks yet. 394 for (uptr i = 0; i < cs_ret; i++) { 395 if (pc != (uptr)tmp[i]) 396 continue; 397 offset = i; 398 break; 399 } 400 401 stack->size = cs_ret - offset; 402 for (uptr i = 0; i < stack->size; i++) 403 stack->trace[i] = (uptr)tmp[i + offset]; 404} 405 406void MaybeOpenReportFile() { 407 // Windows doesn't have native fork, and we don't support Cygwin or other 408 // environments that try to fake it, so the initial report_fd will always be 409 // correct. 410} 411 412void RawWrite(const char *buffer) { 413 static const char *kRawWriteError = 414 "RawWrite can't output requested buffer!\n"; 415 uptr length = (uptr)internal_strlen(buffer); 416 if (length != internal_write(report_fd, buffer, length)) { 417 // stderr may be closed, but we may be able to print to the debugger 418 // instead. This is the case when launching a program from Visual Studio, 419 // and the following routine should write to its console. 420 OutputDebugStringA(buffer); 421 } 422} 423 424} // namespace __sanitizer 425 426#endif // _WIN32 427