sanitizer_win.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
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: %s failed to " 84 "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n", 85 SanitizerToolName, size, size, mem_type, GetLastError()); 86 CHECK("unable to mmap" && 0); 87 } 88 return rv; 89} 90 91void UnmapOrDie(void *addr, uptr size) { 92 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 93 Report("ERROR: %s failed to " 94 "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", 95 SanitizerToolName, size, size, addr, GetLastError()); 96 CHECK("unable to unmap" && 0); 97 } 98} 99 100void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 101 // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 102 // but on Win64 it does. 103 void *p = VirtualAlloc((LPVOID)fixed_addr, size, 104 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 105 if (p == 0) 106 Report("ERROR: %s failed to " 107 "allocate %p (%zd) bytes at %p (error code: %d)\n", 108 SanitizerToolName, size, size, fixed_addr, GetLastError()); 109 return p; 110} 111 112void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 113 return MmapFixedNoReserve(fixed_addr, size); 114} 115 116void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 117 // FIXME: make this really NoReserve? 118 return MmapOrDie(size, mem_type); 119} 120 121void *Mprotect(uptr fixed_addr, uptr size) { 122 return VirtualAlloc((LPVOID)fixed_addr, size, 123 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 124} 125 126void FlushUnneededShadowMemory(uptr addr, uptr size) { 127 // This is almost useless on 32-bits. 128 // FIXME: add madvice-analog when we move to 64-bits. 129} 130 131bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 132 // FIXME: shall we do anything here on Windows? 133 return true; 134} 135 136void *MapFileToMemory(const char *file_name, uptr *buff_size) { 137 UNIMPLEMENTED(); 138} 139 140void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { 141 UNIMPLEMENTED(); 142} 143 144static const int kMaxEnvNameLength = 128; 145static const DWORD kMaxEnvValueLength = 32767; 146 147namespace { 148 149struct EnvVariable { 150 char name[kMaxEnvNameLength]; 151 char value[kMaxEnvValueLength]; 152}; 153 154} // namespace 155 156static const int kEnvVariables = 5; 157static EnvVariable env_vars[kEnvVariables]; 158static int num_env_vars; 159 160const char *GetEnv(const char *name) { 161 // Note: this implementation caches the values of the environment variables 162 // and limits their quantity. 163 for (int i = 0; i < num_env_vars; i++) { 164 if (0 == internal_strcmp(name, env_vars[i].name)) 165 return env_vars[i].value; 166 } 167 CHECK_LT(num_env_vars, kEnvVariables); 168 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 169 kMaxEnvValueLength); 170 if (rv > 0 && rv < kMaxEnvValueLength) { 171 CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 172 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 173 num_env_vars++; 174 return env_vars[num_env_vars - 1].value; 175 } 176 return 0; 177} 178 179const char *GetPwd() { 180 UNIMPLEMENTED(); 181} 182 183u32 GetUid() { 184 UNIMPLEMENTED(); 185} 186 187void DumpProcessMap() { 188 UNIMPLEMENTED(); 189} 190 191void DisableCoreDumper() { 192 // Do nothing. 193} 194 195void ReExec() { 196 UNIMPLEMENTED(); 197} 198 199void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 200 (void)args; 201 // Nothing here for now. 202} 203 204bool StackSizeIsUnlimited() { 205 UNIMPLEMENTED(); 206} 207 208void SetStackSizeLimitInBytes(uptr limit) { 209 UNIMPLEMENTED(); 210} 211 212char *FindPathToBinary(const char *name) { 213 // Nothing here for now. 214 return 0; 215} 216 217void SleepForSeconds(int seconds) { 218 Sleep(seconds * 1000); 219} 220 221void SleepForMillis(int millis) { 222 Sleep(millis); 223} 224 225u64 NanoTime() { 226 return 0; 227} 228 229void Abort() { 230 abort(); 231 internal__exit(-1); // abort is not NORETURN on Windows. 232} 233 234uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 235 string_predicate_t filter) { 236 UNIMPLEMENTED(); 237}; 238 239#ifndef SANITIZER_GO 240int Atexit(void (*function)(void)) { 241 return atexit(function); 242} 243#endif 244 245// ------------------ sanitizer_libc.h 246uptr internal_mmap(void *addr, uptr length, int prot, int flags, 247 int fd, u64 offset) { 248 UNIMPLEMENTED(); 249} 250 251uptr internal_munmap(void *addr, uptr length) { 252 UNIMPLEMENTED(); 253} 254 255uptr internal_close(fd_t fd) { 256 UNIMPLEMENTED(); 257} 258 259int internal_isatty(fd_t fd) { 260 return _isatty(fd); 261} 262 263uptr internal_open(const char *filename, int flags) { 264 UNIMPLEMENTED(); 265} 266 267uptr internal_open(const char *filename, int flags, u32 mode) { 268 UNIMPLEMENTED(); 269} 270 271uptr OpenFile(const char *filename, bool write) { 272 UNIMPLEMENTED(); 273} 274 275uptr internal_read(fd_t fd, void *buf, uptr count) { 276 UNIMPLEMENTED(); 277} 278 279uptr internal_write(fd_t fd, const void *buf, uptr count) { 280 if (fd != kStderrFd) 281 UNIMPLEMENTED(); 282 283 static HANDLE output_stream = 0; 284 // Abort immediately if we know printing is not possible. 285 if (output_stream == INVALID_HANDLE_VALUE) 286 return 0; 287 288 // If called for the first time, try to use stderr to output stuff, 289 // falling back to stdout if anything goes wrong. 290 bool fallback_to_stdout = false; 291 if (output_stream == 0) { 292 output_stream = GetStdHandle(STD_ERROR_HANDLE); 293 // We don't distinguish "no such handle" from error. 294 if (output_stream == 0) 295 output_stream = INVALID_HANDLE_VALUE; 296 297 if (output_stream == INVALID_HANDLE_VALUE) { 298 // Retry with stdout? 299 output_stream = GetStdHandle(STD_OUTPUT_HANDLE); 300 if (output_stream == 0) 301 output_stream = INVALID_HANDLE_VALUE; 302 if (output_stream == INVALID_HANDLE_VALUE) 303 return 0; 304 } else { 305 // Successfully got an stderr handle. However, if WriteFile() fails, 306 // we can still try to fallback to stdout. 307 fallback_to_stdout = true; 308 } 309 } 310 311 DWORD ret; 312 if (WriteFile(output_stream, buf, count, &ret, 0)) 313 return ret; 314 315 // Re-try with stdout if using a valid stderr handle fails. 316 if (fallback_to_stdout) { 317 output_stream = GetStdHandle(STD_OUTPUT_HANDLE); 318 if (output_stream == 0) 319 output_stream = INVALID_HANDLE_VALUE; 320 if (output_stream != INVALID_HANDLE_VALUE) 321 return internal_write(fd, buf, count); 322 } 323 return 0; 324} 325 326uptr internal_stat(const char *path, void *buf) { 327 UNIMPLEMENTED(); 328} 329 330uptr internal_lstat(const char *path, void *buf) { 331 UNIMPLEMENTED(); 332} 333 334uptr internal_fstat(fd_t fd, void *buf) { 335 UNIMPLEMENTED(); 336} 337 338uptr internal_filesize(fd_t fd) { 339 UNIMPLEMENTED(); 340} 341 342uptr internal_dup2(int oldfd, int newfd) { 343 UNIMPLEMENTED(); 344} 345 346uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 347 UNIMPLEMENTED(); 348} 349 350uptr internal_sched_yield() { 351 Sleep(0); 352 return 0; 353} 354 355void internal__exit(int exitcode) { 356 ExitProcess(exitcode); 357} 358 359uptr internal_ftruncate(fd_t fd, uptr size) { 360 UNIMPLEMENTED(); 361} 362 363uptr internal_rename(const char *oldpath, const char *newpath) { 364 UNIMPLEMENTED(); 365} 366 367// ---------------------- BlockingMutex ---------------- {{{1 368const uptr LOCK_UNINITIALIZED = 0; 369const uptr LOCK_READY = (uptr)-1; 370 371BlockingMutex::BlockingMutex(LinkerInitialized li) { 372 // FIXME: see comments in BlockingMutex::Lock() for the details. 373 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 374 375 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 376 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 377 owner_ = LOCK_READY; 378} 379 380BlockingMutex::BlockingMutex() { 381 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 382 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 383 owner_ = LOCK_READY; 384} 385 386void BlockingMutex::Lock() { 387 if (owner_ == LOCK_UNINITIALIZED) { 388 // FIXME: hm, global BlockingMutex objects are not initialized?!? 389 // This might be a side effect of the clang+cl+link Frankenbuild... 390 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); 391 392 // FIXME: If it turns out the linker doesn't invoke our 393 // constructors, we should probably manually Lock/Unlock all the global 394 // locks while we're starting in one thread to avoid double-init races. 395 } 396 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 397 CHECK_EQ(owner_, LOCK_READY); 398 owner_ = GetThreadSelf(); 399} 400 401void BlockingMutex::Unlock() { 402 CHECK_EQ(owner_, GetThreadSelf()); 403 owner_ = LOCK_READY; 404 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 405} 406 407void BlockingMutex::CheckLocked() { 408 CHECK_EQ(owner_, GetThreadSelf()); 409} 410 411uptr GetTlsSize() { 412 return 0; 413} 414 415void InitTlsSize() { 416} 417 418void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 419 uptr *tls_addr, uptr *tls_size) { 420#ifdef SANITIZER_GO 421 *stk_addr = 0; 422 *stk_size = 0; 423 *tls_addr = 0; 424 *tls_size = 0; 425#else 426 uptr stack_top, stack_bottom; 427 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 428 *stk_addr = stack_bottom; 429 *stk_size = stack_top - stack_bottom; 430 *tls_addr = 0; 431 *tls_size = 0; 432#endif 433} 434 435void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { 436 CHECK_GE(max_depth, 2); 437 // FIXME: CaptureStackBackTrace might be too slow for us. 438 // FIXME: Compare with StackWalk64. 439 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 440 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax), 441 (void**)trace, 0); 442 if (size == 0) 443 return; 444 445 // Skip the RTL frames by searching for the PC in the stacktrace. 446 uptr pc_location = LocatePcInTrace(pc); 447 PopStackFrames(pc_location); 448} 449 450void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, 451 uptr max_depth) { 452 UNREACHABLE("no signal context on windows"); 453} 454 455void MaybeOpenReportFile() { 456 // Windows doesn't have native fork, and we don't support Cygwin or other 457 // environments that try to fake it, so the initial report_fd will always be 458 // correct. 459} 460 461void RawWrite(const char *buffer) { 462 uptr length = (uptr)internal_strlen(buffer); 463 if (length != internal_write(report_fd, buffer, length)) { 464 // stderr may be closed, but we may be able to print to the debugger 465 // instead. This is the case when launching a program from Visual Studio, 466 // and the following routine should write to its console. 467 OutputDebugStringA(buffer); 468 } 469} 470 471void SetAlternateSignalStack() { 472 // FIXME: Decide what to do on Windows. 473} 474 475void UnsetAlternateSignalStack() { 476 // FIXME: Decide what to do on Windows. 477} 478 479void InstallDeadlySignalHandlers(SignalHandlerType handler) { 480 (void)handler; 481 // FIXME: Decide what to do on Windows. 482} 483 484bool IsDeadlySignal(int signum) { 485 // FIXME: Decide what to do on Windows. 486 return false; 487} 488 489} // namespace __sanitizer 490 491#endif // _WIN32 492