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 <windows.h> 21#include <dbghelp.h> 22#include <io.h> 23#include <psapi.h> 24#include <stdlib.h> 25 26#include "sanitizer_common.h" 27#include "sanitizer_libc.h" 28#include "sanitizer_mutex.h" 29#include "sanitizer_placement_new.h" 30#include "sanitizer_stacktrace.h" 31 32namespace __sanitizer { 33 34#include "sanitizer_syscall_generic.inc" 35 36// --------------------- sanitizer_common.h 37uptr GetPageSize() { 38 return 1U << 14; // FIXME: is this configurable? 39} 40 41uptr GetMmapGranularity() { 42 return 1U << 16; // FIXME: is this configurable? 43} 44 45uptr GetMaxVirtualAddress() { 46 SYSTEM_INFO si; 47 GetSystemInfo(&si); 48 return (uptr)si.lpMaximumApplicationAddress; 49} 50 51bool FileExists(const char *filename) { 52 UNIMPLEMENTED(); 53} 54 55uptr internal_getpid() { 56 return GetProcessId(GetCurrentProcess()); 57} 58 59// In contrast to POSIX, on Windows GetCurrentThreadId() 60// returns a system-unique identifier. 61uptr GetTid() { 62 return GetCurrentThreadId(); 63} 64 65uptr GetThreadSelf() { 66 return GetTid(); 67} 68 69#if !SANITIZER_GO 70void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 71 uptr *stack_bottom) { 72 CHECK(stack_top); 73 CHECK(stack_bottom); 74 MEMORY_BASIC_INFORMATION mbi; 75 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); 76 // FIXME: is it possible for the stack to not be a single allocation? 77 // Are these values what ASan expects to get (reserved, not committed; 78 // including stack guard page) ? 79 *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; 80 *stack_bottom = (uptr)mbi.AllocationBase; 81} 82#endif // #if !SANITIZER_GO 83 84void *MmapOrDie(uptr size, const char *mem_type) { 85 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 86 if (rv == 0) { 87 Report("ERROR: %s failed to " 88 "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n", 89 SanitizerToolName, size, size, mem_type, GetLastError()); 90 CHECK("unable to mmap" && 0); 91 } 92 return rv; 93} 94 95void UnmapOrDie(void *addr, uptr size) { 96 if (!size || !addr) 97 return; 98 99 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 100 Report("ERROR: %s failed to " 101 "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", 102 SanitizerToolName, size, size, addr, GetLastError()); 103 CHECK("unable to unmap" && 0); 104 } 105} 106 107void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 108 // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 109 // but on Win64 it does. 110 void *p = VirtualAlloc((LPVOID)fixed_addr, size, 111 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 112 if (p == 0) 113 Report("ERROR: %s failed to " 114 "allocate %p (%zd) bytes at %p (error code: %d)\n", 115 SanitizerToolName, size, size, fixed_addr, GetLastError()); 116 return p; 117} 118 119void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 120 return MmapFixedNoReserve(fixed_addr, size); 121} 122 123void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 124 // FIXME: make this really NoReserve? 125 return MmapOrDie(size, mem_type); 126} 127 128void *MmapNoAccess(uptr fixed_addr, uptr size) { 129 void *res = VirtualAlloc((LPVOID)fixed_addr, size, 130 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 131 if (res == 0) 132 Report("WARNING: %s failed to " 133 "mprotect %p (%zd) bytes at %p (error code: %d)\n", 134 SanitizerToolName, size, size, fixed_addr, GetLastError()); 135 return res; 136} 137 138bool MprotectNoAccess(uptr addr, uptr size) { 139 DWORD old_protection; 140 return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); 141} 142 143 144void FlushUnneededShadowMemory(uptr addr, uptr size) { 145 // This is almost useless on 32-bits. 146 // FIXME: add madvise-analog when we move to 64-bits. 147} 148 149void NoHugePagesInRegion(uptr addr, uptr size) { 150 // FIXME: probably similar to FlushUnneededShadowMemory. 151} 152 153void DontDumpShadowMemory(uptr addr, uptr length) { 154 // This is almost useless on 32-bits. 155 // FIXME: add madvise-analog when we move to 64-bits. 156} 157 158bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 159 MEMORY_BASIC_INFORMATION mbi; 160 CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); 161 return mbi.Protect == PAGE_NOACCESS && 162 (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; 163} 164 165void *MapFileToMemory(const char *file_name, uptr *buff_size) { 166 UNIMPLEMENTED(); 167} 168 169void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) { 170 UNIMPLEMENTED(); 171} 172 173static const int kMaxEnvNameLength = 128; 174static const DWORD kMaxEnvValueLength = 32767; 175 176namespace { 177 178struct EnvVariable { 179 char name[kMaxEnvNameLength]; 180 char value[kMaxEnvValueLength]; 181}; 182 183} // namespace 184 185static const int kEnvVariables = 5; 186static EnvVariable env_vars[kEnvVariables]; 187static int num_env_vars; 188 189const char *GetEnv(const char *name) { 190 // Note: this implementation caches the values of the environment variables 191 // and limits their quantity. 192 for (int i = 0; i < num_env_vars; i++) { 193 if (0 == internal_strcmp(name, env_vars[i].name)) 194 return env_vars[i].value; 195 } 196 CHECK_LT(num_env_vars, kEnvVariables); 197 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 198 kMaxEnvValueLength); 199 if (rv > 0 && rv < kMaxEnvValueLength) { 200 CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 201 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 202 num_env_vars++; 203 return env_vars[num_env_vars - 1].value; 204 } 205 return 0; 206} 207 208const char *GetPwd() { 209 UNIMPLEMENTED(); 210} 211 212u32 GetUid() { 213 UNIMPLEMENTED(); 214} 215 216namespace { 217struct ModuleInfo { 218 const char *filepath; 219 uptr base_address; 220 uptr end_address; 221}; 222 223int CompareModulesBase(const void *pl, const void *pr) { 224 const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr; 225 if (l->base_address < r->base_address) 226 return -1; 227 return l->base_address > r->base_address; 228} 229} // namespace 230 231#ifndef SANITIZER_GO 232void DumpProcessMap() { 233 Report("Dumping process modules:\n"); 234 InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules); 235 uptr num_modules = 236 GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr); 237 238 InternalScopedBuffer<ModuleInfo> module_infos(num_modules); 239 for (size_t i = 0; i < num_modules; ++i) { 240 module_infos[i].filepath = modules[i].full_name(); 241 module_infos[i].base_address = modules[i].base_address(); 242 module_infos[i].end_address = modules[i].ranges().next()->end; 243 } 244 qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), 245 CompareModulesBase); 246 247 for (size_t i = 0; i < num_modules; ++i) { 248 const ModuleInfo &mi = module_infos[i]; 249 if (mi.end_address != 0) { 250 Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, 251 mi.filepath[0] ? mi.filepath : "[no name]"); 252 } else if (mi.filepath[0]) { 253 Printf("\t??\?-??? %s\n", mi.filepath); 254 } else { 255 Printf("\t???\n"); 256 } 257 } 258} 259#endif 260 261void DisableCoreDumperIfNecessary() { 262 // Do nothing. 263} 264 265void ReExec() { 266 UNIMPLEMENTED(); 267} 268 269void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 270 (void)args; 271 // Nothing here for now. 272} 273 274bool StackSizeIsUnlimited() { 275 UNIMPLEMENTED(); 276} 277 278void SetStackSizeLimitInBytes(uptr limit) { 279 UNIMPLEMENTED(); 280} 281 282bool AddressSpaceIsUnlimited() { 283 UNIMPLEMENTED(); 284} 285 286void SetAddressSpaceUnlimited() { 287 UNIMPLEMENTED(); 288} 289 290char *FindPathToBinary(const char *name) { 291 // Nothing here for now. 292 return 0; 293} 294 295uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 296 // Nothing here for now. 297 return 0; 298} 299 300bool IsPathSeparator(const char c) { 301 return c == '\\' || c == '/'; 302} 303 304bool IsAbsolutePath(const char *path) { 305 UNIMPLEMENTED(); 306} 307 308void SleepForSeconds(int seconds) { 309 Sleep(seconds * 1000); 310} 311 312void SleepForMillis(int millis) { 313 Sleep(millis); 314} 315 316u64 NanoTime() { 317 return 0; 318} 319 320void Abort() { 321 if (::IsDebuggerPresent()) 322 __debugbreak(); 323 internal__exit(3); 324} 325 326uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 327 string_predicate_t filter) { 328 HANDLE cur_process = GetCurrentProcess(); 329 330 // Query the list of modules. Start by assuming there are no more than 256 331 // modules and retry if that's not sufficient. 332 HMODULE *hmodules = 0; 333 uptr modules_buffer_size = sizeof(HMODULE) * 256; 334 DWORD bytes_required; 335 while (!hmodules) { 336 hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); 337 CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, 338 &bytes_required)); 339 if (bytes_required > modules_buffer_size) { 340 // Either there turned out to be more than 256 hmodules, or new hmodules 341 // could have loaded since the last try. Retry. 342 UnmapOrDie(hmodules, modules_buffer_size); 343 hmodules = 0; 344 modules_buffer_size = bytes_required; 345 } 346 } 347 348 // |num_modules| is the number of modules actually present, 349 // |count| is the number of modules we return. 350 size_t nun_modules = bytes_required / sizeof(HMODULE), 351 count = 0; 352 for (size_t i = 0; i < nun_modules && count < max_modules; ++i) { 353 HMODULE handle = hmodules[i]; 354 MODULEINFO mi; 355 if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) 356 continue; 357 358 char module_name[MAX_PATH]; 359 bool got_module_name = 360 GetModuleFileNameA(handle, module_name, sizeof(module_name)); 361 if (!got_module_name) 362 module_name[0] = '\0'; 363 364 if (filter && !filter(module_name)) 365 continue; 366 367 uptr base_address = (uptr)mi.lpBaseOfDll; 368 uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; 369 LoadedModule *cur_module = &modules[count]; 370 cur_module->set(module_name, base_address); 371 // We add the whole module as one single address range. 372 cur_module->addAddressRange(base_address, end_address, /*executable*/ true); 373 count++; 374 } 375 UnmapOrDie(hmodules, modules_buffer_size); 376 377 return count; 378}; 379 380#ifndef SANITIZER_GO 381// We can't use atexit() directly at __asan_init time as the CRT is not fully 382// initialized at this point. Place the functions into a vector and use 383// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). 384InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; 385 386int Atexit(void (*function)(void)) { 387 atexit_functions.push_back(function); 388 return 0; 389} 390 391static int RunAtexit() { 392 int ret = 0; 393 for (uptr i = 0; i < atexit_functions.size(); ++i) { 394 ret |= atexit(atexit_functions[i]); 395 } 396 return ret; 397} 398 399#pragma section(".CRT$XID", long, read) // NOLINT 400static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; 401#endif 402 403// ------------------ sanitizer_libc.h 404fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { 405 if (mode != WrOnly) 406 UNIMPLEMENTED(); 407 fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 408 FILE_ATTRIBUTE_NORMAL, nullptr); 409 CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); 410 CHECK(res != kStderrFd || kStderrFd == kInvalidFd); 411 return res; 412} 413 414void CloseFile(fd_t fd) { 415 CloseHandle(fd); 416} 417 418bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 419 error_t *error_p) { 420 UNIMPLEMENTED(); 421} 422 423bool SupportsColoredOutput(fd_t fd) { 424 // FIXME: support colored output. 425 return false; 426} 427 428bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 429 error_t *error_p) { 430 CHECK(fd != kInvalidFd); 431 432 if (fd == kStdoutFd) { 433 fd = GetStdHandle(STD_OUTPUT_HANDLE); 434 if (fd == 0) fd = kInvalidFd; 435 } else if (fd == kStderrFd) { 436 fd = GetStdHandle(STD_ERROR_HANDLE); 437 if (fd == 0) fd = kInvalidFd; 438 } 439 440 DWORD internal_bytes_written; 441 if (fd == kInvalidFd || 442 WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) { 443 if (error_p) *error_p = GetLastError(); 444 return false; 445 } else { 446 if (bytes_written) *bytes_written = internal_bytes_written; 447 return true; 448 } 449} 450 451bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) { 452 UNIMPLEMENTED(); 453} 454 455uptr internal_sched_yield() { 456 Sleep(0); 457 return 0; 458} 459 460void internal__exit(int exitcode) { 461 ExitProcess(exitcode); 462} 463 464uptr internal_ftruncate(fd_t fd, uptr size) { 465 UNIMPLEMENTED(); 466} 467 468uptr GetRSS() { 469 return 0; 470} 471 472void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } 473void internal_join_thread(void *th) { } 474 475// ---------------------- BlockingMutex ---------------- {{{1 476const uptr LOCK_UNINITIALIZED = 0; 477const uptr LOCK_READY = (uptr)-1; 478 479BlockingMutex::BlockingMutex(LinkerInitialized li) { 480 // FIXME: see comments in BlockingMutex::Lock() for the details. 481 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 482 483 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 484 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 485 owner_ = LOCK_READY; 486} 487 488BlockingMutex::BlockingMutex() { 489 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 490 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 491 owner_ = LOCK_READY; 492} 493 494void BlockingMutex::Lock() { 495 if (owner_ == LOCK_UNINITIALIZED) { 496 // FIXME: hm, global BlockingMutex objects are not initialized?!? 497 // This might be a side effect of the clang+cl+link Frankenbuild... 498 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); 499 500 // FIXME: If it turns out the linker doesn't invoke our 501 // constructors, we should probably manually Lock/Unlock all the global 502 // locks while we're starting in one thread to avoid double-init races. 503 } 504 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 505 CHECK_EQ(owner_, LOCK_READY); 506 owner_ = GetThreadSelf(); 507} 508 509void BlockingMutex::Unlock() { 510 CHECK_EQ(owner_, GetThreadSelf()); 511 owner_ = LOCK_READY; 512 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 513} 514 515void BlockingMutex::CheckLocked() { 516 CHECK_EQ(owner_, GetThreadSelf()); 517} 518 519uptr GetTlsSize() { 520 return 0; 521} 522 523void InitTlsSize() { 524} 525 526void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 527 uptr *tls_addr, uptr *tls_size) { 528#ifdef SANITIZER_GO 529 *stk_addr = 0; 530 *stk_size = 0; 531 *tls_addr = 0; 532 *tls_size = 0; 533#else 534 uptr stack_top, stack_bottom; 535 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 536 *stk_addr = stack_bottom; 537 *stk_size = stack_top - stack_bottom; 538 *tls_addr = 0; 539 *tls_size = 0; 540#endif 541} 542 543#if !SANITIZER_GO 544void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { 545 CHECK_GE(max_depth, 2); 546 // FIXME: CaptureStackBackTrace might be too slow for us. 547 // FIXME: Compare with StackWalk64. 548 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 549 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax), 550 (void**)trace, 0); 551 if (size == 0) 552 return; 553 554 // Skip the RTL frames by searching for the PC in the stacktrace. 555 uptr pc_location = LocatePcInTrace(pc); 556 PopStackFrames(pc_location); 557} 558 559void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, 560 u32 max_depth) { 561 CONTEXT ctx = *(CONTEXT *)context; 562 STACKFRAME64 stack_frame; 563 memset(&stack_frame, 0, sizeof(stack_frame)); 564 size = 0; 565#if defined(_WIN64) 566 int machine_type = IMAGE_FILE_MACHINE_AMD64; 567 stack_frame.AddrPC.Offset = ctx.Rip; 568 stack_frame.AddrFrame.Offset = ctx.Rbp; 569 stack_frame.AddrStack.Offset = ctx.Rsp; 570#else 571 int machine_type = IMAGE_FILE_MACHINE_I386; 572 stack_frame.AddrPC.Offset = ctx.Eip; 573 stack_frame.AddrFrame.Offset = ctx.Ebp; 574 stack_frame.AddrStack.Offset = ctx.Esp; 575#endif 576 stack_frame.AddrPC.Mode = AddrModeFlat; 577 stack_frame.AddrFrame.Mode = AddrModeFlat; 578 stack_frame.AddrStack.Mode = AddrModeFlat; 579 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), 580 &stack_frame, &ctx, NULL, &SymFunctionTableAccess64, 581 &SymGetModuleBase64, NULL) && 582 size < Min(max_depth, kStackTraceMax)) { 583 trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; 584 } 585} 586#endif // #if !SANITIZER_GO 587 588void ReportFile::Write(const char *buffer, uptr length) { 589 SpinMutexLock l(mu); 590 ReopenIfNecessary(); 591 if (!WriteToFile(fd, buffer, length)) { 592 // stderr may be closed, but we may be able to print to the debugger 593 // instead. This is the case when launching a program from Visual Studio, 594 // and the following routine should write to its console. 595 OutputDebugStringA(buffer); 596 } 597} 598 599void SetAlternateSignalStack() { 600 // FIXME: Decide what to do on Windows. 601} 602 603void UnsetAlternateSignalStack() { 604 // FIXME: Decide what to do on Windows. 605} 606 607void InstallDeadlySignalHandlers(SignalHandlerType handler) { 608 (void)handler; 609 // FIXME: Decide what to do on Windows. 610} 611 612bool IsDeadlySignal(int signum) { 613 // FIXME: Decide what to do on Windows. 614 return false; 615} 616 617bool IsAccessibleMemoryRange(uptr beg, uptr size) { 618 // FIXME: Actually implement this function. 619 return true; 620} 621 622SignalContext SignalContext::Create(void *siginfo, void *context) { 623 EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; 624 CONTEXT *context_record = (CONTEXT*)context; 625 626 uptr pc = (uptr)exception_record->ExceptionAddress; 627#ifdef _WIN64 628 uptr bp = (uptr)context_record->Rbp; 629 uptr sp = (uptr)context_record->Rsp; 630#else 631 uptr bp = (uptr)context_record->Ebp; 632 uptr sp = (uptr)context_record->Esp; 633#endif 634 uptr access_addr = exception_record->ExceptionInformation[1]; 635 636 return SignalContext(context, access_addr, pc, sp, bp); 637} 638 639} // namespace __sanitizer 640 641#endif // _WIN32 642