1353944Sdim//===-- sanitizer_win.cpp -------------------------------------------------===// 2353944Sdim// 3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353944Sdim// See https://llvm.org/LICENSE.txt for license information. 5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353944Sdim// 7353944Sdim//===----------------------------------------------------------------------===// 8353944Sdim// 9353944Sdim// This file is shared between AddressSanitizer and ThreadSanitizer 10353944Sdim// run-time libraries and implements windows-specific functions from 11353944Sdim// sanitizer_libc.h. 12353944Sdim//===----------------------------------------------------------------------===// 13353944Sdim 14353944Sdim#include "sanitizer_platform.h" 15353944Sdim#if SANITIZER_WINDOWS 16353944Sdim 17353944Sdim#define WIN32_LEAN_AND_MEAN 18353944Sdim#define NOGDI 19353944Sdim#include <windows.h> 20353944Sdim#include <io.h> 21353944Sdim#include <psapi.h> 22353944Sdim#include <stdlib.h> 23353944Sdim 24353944Sdim#include "sanitizer_common.h" 25353944Sdim#include "sanitizer_file.h" 26353944Sdim#include "sanitizer_libc.h" 27353944Sdim#include "sanitizer_mutex.h" 28353944Sdim#include "sanitizer_placement_new.h" 29353944Sdim#include "sanitizer_win_defs.h" 30353944Sdim 31353944Sdim#if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 32353944Sdim#pragma comment(lib, "psapi") 33353944Sdim#endif 34353944Sdim#if SANITIZER_WIN_TRACE 35353944Sdim#include <traceloggingprovider.h> 36353944Sdim// Windows trace logging provider init 37353944Sdim#pragma comment(lib, "advapi32.lib") 38353944SdimTRACELOGGING_DECLARE_PROVIDER(g_asan_provider); 39353944Sdim// GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp 40353944SdimTRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", 41353944Sdim (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, 42353944Sdim 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); 43353944Sdim#else 44353944Sdim#define TraceLoggingUnregister(x) 45353944Sdim#endif 46353944Sdim 47353944Sdim// A macro to tell the compiler that this part of the code cannot be reached, 48353944Sdim// if the compiler supports this feature. Since we're using this in 49353944Sdim// code that is called when terminating the process, the expansion of the 50353944Sdim// macro should not terminate the process to avoid infinite recursion. 51353944Sdim#if defined(__clang__) 52353944Sdim# define BUILTIN_UNREACHABLE() __builtin_unreachable() 53353944Sdim#elif defined(__GNUC__) && \ 54353944Sdim (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) 55353944Sdim# define BUILTIN_UNREACHABLE() __builtin_unreachable() 56353944Sdim#elif defined(_MSC_VER) 57353944Sdim# define BUILTIN_UNREACHABLE() __assume(0) 58353944Sdim#else 59353944Sdim# define BUILTIN_UNREACHABLE() 60353944Sdim#endif 61353944Sdim 62353944Sdimnamespace __sanitizer { 63353944Sdim 64353944Sdim#include "sanitizer_syscall_generic.inc" 65353944Sdim 66353944Sdim// --------------------- sanitizer_common.h 67353944Sdimuptr GetPageSize() { 68353944Sdim SYSTEM_INFO si; 69353944Sdim GetSystemInfo(&si); 70353944Sdim return si.dwPageSize; 71353944Sdim} 72353944Sdim 73353944Sdimuptr GetMmapGranularity() { 74353944Sdim SYSTEM_INFO si; 75353944Sdim GetSystemInfo(&si); 76353944Sdim return si.dwAllocationGranularity; 77353944Sdim} 78353944Sdim 79353944Sdimuptr GetMaxUserVirtualAddress() { 80353944Sdim SYSTEM_INFO si; 81353944Sdim GetSystemInfo(&si); 82353944Sdim return (uptr)si.lpMaximumApplicationAddress; 83353944Sdim} 84353944Sdim 85353944Sdimuptr GetMaxVirtualAddress() { 86353944Sdim return GetMaxUserVirtualAddress(); 87353944Sdim} 88353944Sdim 89353944Sdimbool FileExists(const char *filename) { 90353944Sdim return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; 91353944Sdim} 92353944Sdim 93353944Sdimuptr internal_getpid() { 94353944Sdim return GetProcessId(GetCurrentProcess()); 95353944Sdim} 96353944Sdim 97353944Sdim// In contrast to POSIX, on Windows GetCurrentThreadId() 98353944Sdim// returns a system-unique identifier. 99353944Sdimtid_t GetTid() { 100353944Sdim return GetCurrentThreadId(); 101353944Sdim} 102353944Sdim 103353944Sdimuptr GetThreadSelf() { 104353944Sdim return GetTid(); 105353944Sdim} 106353944Sdim 107353944Sdim#if !SANITIZER_GO 108353944Sdimvoid GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 109353944Sdim uptr *stack_bottom) { 110353944Sdim CHECK(stack_top); 111353944Sdim CHECK(stack_bottom); 112353944Sdim MEMORY_BASIC_INFORMATION mbi; 113353944Sdim CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); 114353944Sdim // FIXME: is it possible for the stack to not be a single allocation? 115353944Sdim // Are these values what ASan expects to get (reserved, not committed; 116353944Sdim // including stack guard page) ? 117353944Sdim *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; 118353944Sdim *stack_bottom = (uptr)mbi.AllocationBase; 119353944Sdim} 120353944Sdim#endif // #if !SANITIZER_GO 121353944Sdim 122353944Sdimvoid *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { 123353944Sdim void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 124353944Sdim if (rv == 0) 125353944Sdim ReportMmapFailureAndDie(size, mem_type, "allocate", 126353944Sdim GetLastError(), raw_report); 127353944Sdim return rv; 128353944Sdim} 129353944Sdim 130353944Sdimvoid UnmapOrDie(void *addr, uptr size) { 131353944Sdim if (!size || !addr) 132353944Sdim return; 133353944Sdim 134353944Sdim MEMORY_BASIC_INFORMATION mbi; 135353944Sdim CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); 136353944Sdim 137353944Sdim // MEM_RELEASE can only be used to unmap whole regions previously mapped with 138353944Sdim // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that 139353944Sdim // fails try MEM_DECOMMIT. 140353944Sdim if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { 141353944Sdim if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 142353944Sdim Report("ERROR: %s failed to " 143353944Sdim "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", 144353944Sdim SanitizerToolName, size, size, addr, GetLastError()); 145353944Sdim CHECK("unable to unmap" && 0); 146353944Sdim } 147353944Sdim } 148353944Sdim} 149353944Sdim 150353944Sdimstatic void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, 151353944Sdim const char *mmap_type) { 152353944Sdim error_t last_error = GetLastError(); 153353944Sdim if (last_error == ERROR_NOT_ENOUGH_MEMORY) 154353944Sdim return nullptr; 155353944Sdim ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); 156353944Sdim} 157353944Sdim 158353944Sdimvoid *MmapOrDieOnFatalError(uptr size, const char *mem_type) { 159353944Sdim void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 160353944Sdim if (rv == 0) 161353944Sdim return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); 162353944Sdim return rv; 163353944Sdim} 164353944Sdim 165353944Sdim// We want to map a chunk of address space aligned to 'alignment'. 166353944Sdimvoid *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, 167353944Sdim const char *mem_type) { 168353944Sdim CHECK(IsPowerOfTwo(size)); 169353944Sdim CHECK(IsPowerOfTwo(alignment)); 170353944Sdim 171353944Sdim // Windows will align our allocations to at least 64K. 172353944Sdim alignment = Max(alignment, GetMmapGranularity()); 173353944Sdim 174353944Sdim uptr mapped_addr = 175353944Sdim (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 176353944Sdim if (!mapped_addr) 177353944Sdim return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 178353944Sdim 179353944Sdim // If we got it right on the first try, return. Otherwise, unmap it and go to 180353944Sdim // the slow path. 181353944Sdim if (IsAligned(mapped_addr, alignment)) 182353944Sdim return (void*)mapped_addr; 183353944Sdim if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) 184353944Sdim ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); 185353944Sdim 186353944Sdim // If we didn't get an aligned address, overallocate, find an aligned address, 187353944Sdim // unmap, and try to allocate at that aligned address. 188353944Sdim int retries = 0; 189353944Sdim const int kMaxRetries = 10; 190353944Sdim for (; retries < kMaxRetries && 191353944Sdim (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); 192353944Sdim retries++) { 193353944Sdim // Overallocate size + alignment bytes. 194353944Sdim mapped_addr = 195353944Sdim (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); 196353944Sdim if (!mapped_addr) 197353944Sdim return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 198353944Sdim 199353944Sdim // Find the aligned address. 200353944Sdim uptr aligned_addr = RoundUpTo(mapped_addr, alignment); 201353944Sdim 202353944Sdim // Free the overallocation. 203353944Sdim if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) 204353944Sdim ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); 205353944Sdim 206353944Sdim // Attempt to allocate exactly the number of bytes we need at the aligned 207353944Sdim // address. This may fail for a number of reasons, in which case we continue 208353944Sdim // the loop. 209353944Sdim mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, 210353944Sdim MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 211353944Sdim } 212353944Sdim 213353944Sdim // Fail if we can't make this work quickly. 214353944Sdim if (retries == kMaxRetries && mapped_addr == 0) 215353944Sdim return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 216353944Sdim 217353944Sdim return (void *)mapped_addr; 218353944Sdim} 219353944Sdim 220353944Sdimbool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { 221353944Sdim // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 222353944Sdim // but on Win64 it does. 223353944Sdim (void)name; // unsupported 224353944Sdim#if !SANITIZER_GO && SANITIZER_WINDOWS64 225353944Sdim // On asan/Windows64, use MEM_COMMIT would result in error 226353944Sdim // 1455:ERROR_COMMITMENT_LIMIT. 227353944Sdim // Asan uses exception handler to commit page on demand. 228353944Sdim void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); 229353944Sdim#else 230353944Sdim void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, 231353944Sdim PAGE_READWRITE); 232353944Sdim#endif 233353944Sdim if (p == 0) { 234353944Sdim Report("ERROR: %s failed to " 235353944Sdim "allocate %p (%zd) bytes at %p (error code: %d)\n", 236353944Sdim SanitizerToolName, size, size, fixed_addr, GetLastError()); 237353944Sdim return false; 238353944Sdim } 239353944Sdim return true; 240353944Sdim} 241353944Sdim 242353944Sdimbool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { 243353944Sdim // FIXME: Windows support large pages too. Might be worth checking 244353944Sdim return MmapFixedNoReserve(fixed_addr, size, name); 245353944Sdim} 246353944Sdim 247353944Sdim// Memory space mapped by 'MmapFixedOrDie' must have been reserved by 248353944Sdim// 'MmapFixedNoAccess'. 249353944Sdimvoid *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { 250353944Sdim void *p = VirtualAlloc((LPVOID)fixed_addr, size, 251353944Sdim MEM_COMMIT, PAGE_READWRITE); 252353944Sdim if (p == 0) { 253353944Sdim char mem_type[30]; 254353944Sdim internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 255353944Sdim fixed_addr); 256353944Sdim ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); 257353944Sdim } 258353944Sdim return p; 259353944Sdim} 260353944Sdim 261353944Sdim// Uses fixed_addr for now. 262353944Sdim// Will use offset instead once we've implemented this function for real. 263353944Sdimuptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { 264353944Sdim return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size)); 265353944Sdim} 266353944Sdim 267353944Sdimuptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, 268353944Sdim const char *name) { 269353944Sdim return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size)); 270353944Sdim} 271353944Sdim 272353944Sdimvoid ReservedAddressRange::Unmap(uptr addr, uptr size) { 273353944Sdim // Only unmap if it covers the entire range. 274353944Sdim CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_)); 275353944Sdim // We unmap the whole range, just null out the base. 276353944Sdim base_ = nullptr; 277353944Sdim size_ = 0; 278353944Sdim UnmapOrDie(reinterpret_cast<void*>(addr), size); 279353944Sdim} 280353944Sdim 281353944Sdimvoid *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { 282353944Sdim void *p = VirtualAlloc((LPVOID)fixed_addr, size, 283353944Sdim MEM_COMMIT, PAGE_READWRITE); 284353944Sdim if (p == 0) { 285353944Sdim char mem_type[30]; 286353944Sdim internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 287353944Sdim fixed_addr); 288353944Sdim return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); 289353944Sdim } 290353944Sdim return p; 291353944Sdim} 292353944Sdim 293353944Sdimvoid *MmapNoReserveOrDie(uptr size, const char *mem_type) { 294353944Sdim // FIXME: make this really NoReserve? 295353944Sdim return MmapOrDie(size, mem_type); 296353944Sdim} 297353944Sdim 298353944Sdimuptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { 299353944Sdim base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); 300353944Sdim size_ = size; 301353944Sdim name_ = name; 302353944Sdim (void)os_handle_; // unsupported 303353944Sdim return reinterpret_cast<uptr>(base_); 304353944Sdim} 305353944Sdim 306353944Sdim 307353944Sdimvoid *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { 308353944Sdim (void)name; // unsupported 309353944Sdim void *res = VirtualAlloc((LPVOID)fixed_addr, size, 310353944Sdim MEM_RESERVE, PAGE_NOACCESS); 311353944Sdim if (res == 0) 312353944Sdim Report("WARNING: %s failed to " 313353944Sdim "mprotect %p (%zd) bytes at %p (error code: %d)\n", 314353944Sdim SanitizerToolName, size, size, fixed_addr, GetLastError()); 315353944Sdim return res; 316353944Sdim} 317353944Sdim 318353944Sdimvoid *MmapNoAccess(uptr size) { 319353944Sdim void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); 320353944Sdim if (res == 0) 321353944Sdim Report("WARNING: %s failed to " 322353944Sdim "mprotect %p (%zd) bytes (error code: %d)\n", 323353944Sdim SanitizerToolName, size, size, GetLastError()); 324353944Sdim return res; 325353944Sdim} 326353944Sdim 327353944Sdimbool MprotectNoAccess(uptr addr, uptr size) { 328353944Sdim DWORD old_protection; 329353944Sdim return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); 330353944Sdim} 331353944Sdim 332353944Sdimvoid ReleaseMemoryPagesToOS(uptr beg, uptr end) { 333353944Sdim // This is almost useless on 32-bits. 334353944Sdim // FIXME: add madvise-analog when we move to 64-bits. 335353944Sdim} 336353944Sdim 337353944Sdimvoid SetShadowRegionHugePageMode(uptr addr, uptr size) { 338353944Sdim // FIXME: probably similar to ReleaseMemoryToOS. 339353944Sdim} 340353944Sdim 341353944Sdimbool DontDumpShadowMemory(uptr addr, uptr length) { 342353944Sdim // This is almost useless on 32-bits. 343353944Sdim // FIXME: add madvise-analog when we move to 64-bits. 344353944Sdim return true; 345353944Sdim} 346353944Sdim 347353944Sdimuptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, 348353944Sdim uptr *largest_gap_found, 349353944Sdim uptr *max_occupied_addr) { 350353944Sdim uptr address = 0; 351353944Sdim while (true) { 352353944Sdim MEMORY_BASIC_INFORMATION info; 353353944Sdim if (!::VirtualQuery((void*)address, &info, sizeof(info))) 354353944Sdim return 0; 355353944Sdim 356353944Sdim if (info.State == MEM_FREE) { 357353944Sdim uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, 358353944Sdim alignment); 359353944Sdim if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) 360353944Sdim return shadow_address; 361353944Sdim } 362353944Sdim 363353944Sdim // Move to the next region. 364353944Sdim address = (uptr)info.BaseAddress + info.RegionSize; 365353944Sdim } 366353944Sdim return 0; 367353944Sdim} 368353944Sdim 369353944Sdimbool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 370353944Sdim MEMORY_BASIC_INFORMATION mbi; 371353944Sdim CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); 372353944Sdim return mbi.Protect == PAGE_NOACCESS && 373353944Sdim (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; 374353944Sdim} 375353944Sdim 376353944Sdimvoid *MapFileToMemory(const char *file_name, uptr *buff_size) { 377353944Sdim UNIMPLEMENTED(); 378353944Sdim} 379353944Sdim 380353944Sdimvoid *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 381353944Sdim UNIMPLEMENTED(); 382353944Sdim} 383353944Sdim 384353944Sdimstatic const int kMaxEnvNameLength = 128; 385353944Sdimstatic const DWORD kMaxEnvValueLength = 32767; 386353944Sdim 387353944Sdimnamespace { 388353944Sdim 389353944Sdimstruct EnvVariable { 390353944Sdim char name[kMaxEnvNameLength]; 391353944Sdim char value[kMaxEnvValueLength]; 392353944Sdim}; 393353944Sdim 394353944Sdim} // namespace 395353944Sdim 396353944Sdimstatic const int kEnvVariables = 5; 397353944Sdimstatic EnvVariable env_vars[kEnvVariables]; 398353944Sdimstatic int num_env_vars; 399353944Sdim 400353944Sdimconst char *GetEnv(const char *name) { 401353944Sdim // Note: this implementation caches the values of the environment variables 402353944Sdim // and limits their quantity. 403353944Sdim for (int i = 0; i < num_env_vars; i++) { 404353944Sdim if (0 == internal_strcmp(name, env_vars[i].name)) 405353944Sdim return env_vars[i].value; 406353944Sdim } 407353944Sdim CHECK_LT(num_env_vars, kEnvVariables); 408353944Sdim DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 409353944Sdim kMaxEnvValueLength); 410353944Sdim if (rv > 0 && rv < kMaxEnvValueLength) { 411353944Sdim CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 412353944Sdim internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 413353944Sdim num_env_vars++; 414353944Sdim return env_vars[num_env_vars - 1].value; 415353944Sdim } 416353944Sdim return 0; 417353944Sdim} 418353944Sdim 419353944Sdimconst char *GetPwd() { 420353944Sdim UNIMPLEMENTED(); 421353944Sdim} 422353944Sdim 423353944Sdimu32 GetUid() { 424353944Sdim UNIMPLEMENTED(); 425353944Sdim} 426353944Sdim 427353944Sdimnamespace { 428353944Sdimstruct ModuleInfo { 429353944Sdim const char *filepath; 430353944Sdim uptr base_address; 431353944Sdim uptr end_address; 432353944Sdim}; 433353944Sdim 434353944Sdim#if !SANITIZER_GO 435353944Sdimint CompareModulesBase(const void *pl, const void *pr) { 436353944Sdim const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; 437353944Sdim if (l->base_address < r->base_address) 438353944Sdim return -1; 439353944Sdim return l->base_address > r->base_address; 440353944Sdim} 441353944Sdim#endif 442353944Sdim} // namespace 443353944Sdim 444353944Sdim#if !SANITIZER_GO 445353944Sdimvoid DumpProcessMap() { 446353944Sdim Report("Dumping process modules:\n"); 447353944Sdim ListOfModules modules; 448353944Sdim modules.init(); 449353944Sdim uptr num_modules = modules.size(); 450353944Sdim 451353944Sdim InternalMmapVector<ModuleInfo> module_infos(num_modules); 452353944Sdim for (size_t i = 0; i < num_modules; ++i) { 453353944Sdim module_infos[i].filepath = modules[i].full_name(); 454353944Sdim module_infos[i].base_address = modules[i].ranges().front()->beg; 455353944Sdim module_infos[i].end_address = modules[i].ranges().back()->end; 456353944Sdim } 457353944Sdim qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), 458353944Sdim CompareModulesBase); 459353944Sdim 460353944Sdim for (size_t i = 0; i < num_modules; ++i) { 461353944Sdim const ModuleInfo &mi = module_infos[i]; 462353944Sdim if (mi.end_address != 0) { 463353944Sdim Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, 464353944Sdim mi.filepath[0] ? mi.filepath : "[no name]"); 465353944Sdim } else if (mi.filepath[0]) { 466353944Sdim Printf("\t??\?-??? %s\n", mi.filepath); 467353944Sdim } else { 468353944Sdim Printf("\t???\n"); 469353944Sdim } 470353944Sdim } 471353944Sdim} 472353944Sdim#endif 473353944Sdim 474353944Sdimvoid PrintModuleMap() { } 475353944Sdim 476353944Sdimvoid DisableCoreDumperIfNecessary() { 477353944Sdim // Do nothing. 478353944Sdim} 479353944Sdim 480353944Sdimvoid ReExec() { 481353944Sdim UNIMPLEMENTED(); 482353944Sdim} 483353944Sdim 484353944Sdimvoid PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} 485353944Sdim 486353944Sdimbool StackSizeIsUnlimited() { 487353944Sdim UNIMPLEMENTED(); 488353944Sdim} 489353944Sdim 490353944Sdimvoid SetStackSizeLimitInBytes(uptr limit) { 491353944Sdim UNIMPLEMENTED(); 492353944Sdim} 493353944Sdim 494353944Sdimbool AddressSpaceIsUnlimited() { 495353944Sdim UNIMPLEMENTED(); 496353944Sdim} 497353944Sdim 498353944Sdimvoid SetAddressSpaceUnlimited() { 499353944Sdim UNIMPLEMENTED(); 500353944Sdim} 501353944Sdim 502353944Sdimbool IsPathSeparator(const char c) { 503353944Sdim return c == '\\' || c == '/'; 504353944Sdim} 505353944Sdim 506353944Sdimstatic bool IsAlpha(char c) { 507353944Sdim c = ToLower(c); 508353944Sdim return c >= 'a' && c <= 'z'; 509353944Sdim} 510353944Sdim 511353944Sdimbool IsAbsolutePath(const char *path) { 512353944Sdim return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && 513353944Sdim IsPathSeparator(path[2]); 514353944Sdim} 515353944Sdim 516353944Sdimvoid SleepForSeconds(int seconds) { 517353944Sdim Sleep(seconds * 1000); 518353944Sdim} 519353944Sdim 520353944Sdimvoid SleepForMillis(int millis) { 521353944Sdim Sleep(millis); 522353944Sdim} 523353944Sdim 524353944Sdimu64 NanoTime() { 525353944Sdim static LARGE_INTEGER frequency = {}; 526353944Sdim LARGE_INTEGER counter; 527353944Sdim if (UNLIKELY(frequency.QuadPart == 0)) { 528353944Sdim QueryPerformanceFrequency(&frequency); 529353944Sdim CHECK_NE(frequency.QuadPart, 0); 530353944Sdim } 531353944Sdim QueryPerformanceCounter(&counter); 532353944Sdim counter.QuadPart *= 1000ULL * 1000000ULL; 533353944Sdim counter.QuadPart /= frequency.QuadPart; 534353944Sdim return counter.QuadPart; 535353944Sdim} 536353944Sdim 537353944Sdimu64 MonotonicNanoTime() { return NanoTime(); } 538353944Sdim 539353944Sdimvoid Abort() { 540353944Sdim internal__exit(3); 541353944Sdim} 542353944Sdim 543353944Sdim#if !SANITIZER_GO 544353944Sdim// Read the file to extract the ImageBase field from the PE header. If ASLR is 545353944Sdim// disabled and this virtual address is available, the loader will typically 546353944Sdim// load the image at this address. Therefore, we call it the preferred base. Any 547353944Sdim// addresses in the DWARF typically assume that the object has been loaded at 548353944Sdim// this address. 549353944Sdimstatic uptr GetPreferredBase(const char *modname) { 550353944Sdim fd_t fd = OpenFile(modname, RdOnly, nullptr); 551353944Sdim if (fd == kInvalidFd) 552353944Sdim return 0; 553353944Sdim FileCloser closer(fd); 554353944Sdim 555353944Sdim // Read just the DOS header. 556353944Sdim IMAGE_DOS_HEADER dos_header; 557353944Sdim uptr bytes_read; 558353944Sdim if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || 559353944Sdim bytes_read != sizeof(dos_header)) 560353944Sdim return 0; 561353944Sdim 562353944Sdim // The file should start with the right signature. 563353944Sdim if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) 564353944Sdim return 0; 565353944Sdim 566353944Sdim // The layout at e_lfanew is: 567353944Sdim // "PE\0\0" 568353944Sdim // IMAGE_FILE_HEADER 569353944Sdim // IMAGE_OPTIONAL_HEADER 570353944Sdim // Seek to e_lfanew and read all that data. 571353944Sdim char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; 572353944Sdim if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == 573353944Sdim INVALID_SET_FILE_POINTER) 574353944Sdim return 0; 575353944Sdim if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || 576353944Sdim bytes_read != sizeof(buf)) 577353944Sdim return 0; 578353944Sdim 579353944Sdim // Check for "PE\0\0" before the PE header. 580353944Sdim char *pe_sig = &buf[0]; 581353944Sdim if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) 582353944Sdim return 0; 583353944Sdim 584353944Sdim // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. 585353944Sdim IMAGE_OPTIONAL_HEADER *pe_header = 586353944Sdim (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); 587353944Sdim 588353944Sdim // Check for more magic in the PE header. 589353944Sdim if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) 590353944Sdim return 0; 591353944Sdim 592353944Sdim // Finally, return the ImageBase. 593353944Sdim return (uptr)pe_header->ImageBase; 594353944Sdim} 595353944Sdim 596353944Sdimvoid ListOfModules::init() { 597353944Sdim clearOrInit(); 598353944Sdim HANDLE cur_process = GetCurrentProcess(); 599353944Sdim 600353944Sdim // Query the list of modules. Start by assuming there are no more than 256 601353944Sdim // modules and retry if that's not sufficient. 602353944Sdim HMODULE *hmodules = 0; 603353944Sdim uptr modules_buffer_size = sizeof(HMODULE) * 256; 604353944Sdim DWORD bytes_required; 605353944Sdim while (!hmodules) { 606353944Sdim hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); 607353944Sdim CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, 608353944Sdim &bytes_required)); 609353944Sdim if (bytes_required > modules_buffer_size) { 610353944Sdim // Either there turned out to be more than 256 hmodules, or new hmodules 611353944Sdim // could have loaded since the last try. Retry. 612353944Sdim UnmapOrDie(hmodules, modules_buffer_size); 613353944Sdim hmodules = 0; 614353944Sdim modules_buffer_size = bytes_required; 615353944Sdim } 616353944Sdim } 617353944Sdim 618353944Sdim // |num_modules| is the number of modules actually present, 619353944Sdim size_t num_modules = bytes_required / sizeof(HMODULE); 620353944Sdim for (size_t i = 0; i < num_modules; ++i) { 621353944Sdim HMODULE handle = hmodules[i]; 622353944Sdim MODULEINFO mi; 623353944Sdim if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) 624353944Sdim continue; 625353944Sdim 626353944Sdim // Get the UTF-16 path and convert to UTF-8. 627353944Sdim wchar_t modname_utf16[kMaxPathLength]; 628353944Sdim int modname_utf16_len = 629353944Sdim GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); 630353944Sdim if (modname_utf16_len == 0) 631353944Sdim modname_utf16[0] = '\0'; 632353944Sdim char module_name[kMaxPathLength]; 633353944Sdim int module_name_len = 634353944Sdim ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, 635353944Sdim &module_name[0], kMaxPathLength, NULL, NULL); 636353944Sdim module_name[module_name_len] = '\0'; 637353944Sdim 638353944Sdim uptr base_address = (uptr)mi.lpBaseOfDll; 639353944Sdim uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; 640353944Sdim 641353944Sdim // Adjust the base address of the module so that we get a VA instead of an 642353944Sdim // RVA when computing the module offset. This helps llvm-symbolizer find the 643353944Sdim // right DWARF CU. In the common case that the image is loaded at it's 644353944Sdim // preferred address, we will now print normal virtual addresses. 645353944Sdim uptr preferred_base = GetPreferredBase(&module_name[0]); 646353944Sdim uptr adjusted_base = base_address - preferred_base; 647353944Sdim 648353944Sdim LoadedModule cur_module; 649353944Sdim cur_module.set(module_name, adjusted_base); 650353944Sdim // We add the whole module as one single address range. 651353944Sdim cur_module.addAddressRange(base_address, end_address, /*executable*/ true, 652353944Sdim /*writable*/ true); 653353944Sdim modules_.push_back(cur_module); 654353944Sdim } 655353944Sdim UnmapOrDie(hmodules, modules_buffer_size); 656353944Sdim} 657353944Sdim 658353944Sdimvoid ListOfModules::fallbackInit() { clear(); } 659353944Sdim 660353944Sdim// We can't use atexit() directly at __asan_init time as the CRT is not fully 661353944Sdim// initialized at this point. Place the functions into a vector and use 662353944Sdim// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). 663353944SdimInternalMmapVectorNoCtor<void (*)(void)> atexit_functions; 664353944Sdim 665353944Sdimint Atexit(void (*function)(void)) { 666353944Sdim atexit_functions.push_back(function); 667353944Sdim return 0; 668353944Sdim} 669353944Sdim 670353944Sdimstatic int RunAtexit() { 671353944Sdim TraceLoggingUnregister(g_asan_provider); 672353944Sdim int ret = 0; 673353944Sdim for (uptr i = 0; i < atexit_functions.size(); ++i) { 674353944Sdim ret |= atexit(atexit_functions[i]); 675353944Sdim } 676353944Sdim return ret; 677353944Sdim} 678353944Sdim 679353944Sdim#pragma section(".CRT$XID", long, read) 680353944Sdim__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; 681353944Sdim#endif 682353944Sdim 683353944Sdim// ------------------ sanitizer_libc.h 684353944Sdimfd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { 685353944Sdim // FIXME: Use the wide variants to handle Unicode filenames. 686353944Sdim fd_t res; 687353944Sdim if (mode == RdOnly) { 688353944Sdim res = CreateFileA(filename, GENERIC_READ, 689353944Sdim FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 690353944Sdim nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 691353944Sdim } else if (mode == WrOnly) { 692353944Sdim res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 693353944Sdim FILE_ATTRIBUTE_NORMAL, nullptr); 694353944Sdim } else { 695353944Sdim UNIMPLEMENTED(); 696353944Sdim } 697353944Sdim CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); 698353944Sdim CHECK(res != kStderrFd || kStderrFd == kInvalidFd); 699353944Sdim if (res == kInvalidFd && last_error) 700353944Sdim *last_error = GetLastError(); 701353944Sdim return res; 702353944Sdim} 703353944Sdim 704353944Sdimvoid CloseFile(fd_t fd) { 705353944Sdim CloseHandle(fd); 706353944Sdim} 707353944Sdim 708353944Sdimbool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 709353944Sdim error_t *error_p) { 710353944Sdim CHECK(fd != kInvalidFd); 711353944Sdim 712353944Sdim // bytes_read can't be passed directly to ReadFile: 713353944Sdim // uptr is unsigned long long on 64-bit Windows. 714353944Sdim unsigned long num_read_long; 715353944Sdim 716353944Sdim bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); 717353944Sdim if (!success && error_p) 718353944Sdim *error_p = GetLastError(); 719353944Sdim if (bytes_read) 720353944Sdim *bytes_read = num_read_long; 721353944Sdim return success; 722353944Sdim} 723353944Sdim 724353944Sdimbool SupportsColoredOutput(fd_t fd) { 725353944Sdim // FIXME: support colored output. 726353944Sdim return false; 727353944Sdim} 728353944Sdim 729353944Sdimbool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 730353944Sdim error_t *error_p) { 731353944Sdim CHECK(fd != kInvalidFd); 732353944Sdim 733353944Sdim // Handle null optional parameters. 734353944Sdim error_t dummy_error; 735353944Sdim error_p = error_p ? error_p : &dummy_error; 736353944Sdim uptr dummy_bytes_written; 737353944Sdim bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; 738353944Sdim 739353944Sdim // Initialize output parameters in case we fail. 740353944Sdim *error_p = 0; 741353944Sdim *bytes_written = 0; 742353944Sdim 743353944Sdim // Map the conventional Unix fds 1 and 2 to Windows handles. They might be 744353944Sdim // closed, in which case this will fail. 745353944Sdim if (fd == kStdoutFd || fd == kStderrFd) { 746353944Sdim fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); 747353944Sdim if (fd == 0) { 748353944Sdim *error_p = ERROR_INVALID_HANDLE; 749353944Sdim return false; 750353944Sdim } 751353944Sdim } 752353944Sdim 753353944Sdim DWORD bytes_written_32; 754353944Sdim if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { 755353944Sdim *error_p = GetLastError(); 756353944Sdim return false; 757353944Sdim } else { 758353944Sdim *bytes_written = bytes_written_32; 759353944Sdim return true; 760353944Sdim } 761353944Sdim} 762353944Sdim 763353944Sdimuptr internal_sched_yield() { 764353944Sdim Sleep(0); 765353944Sdim return 0; 766353944Sdim} 767353944Sdim 768353944Sdimvoid internal__exit(int exitcode) { 769353944Sdim TraceLoggingUnregister(g_asan_provider); 770353944Sdim // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. 771353944Sdim // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, 772353944Sdim // so add our own breakpoint here. 773353944Sdim if (::IsDebuggerPresent()) 774353944Sdim __debugbreak(); 775353944Sdim TerminateProcess(GetCurrentProcess(), exitcode); 776353944Sdim BUILTIN_UNREACHABLE(); 777353944Sdim} 778353944Sdim 779353944Sdimuptr internal_ftruncate(fd_t fd, uptr size) { 780353944Sdim UNIMPLEMENTED(); 781353944Sdim} 782353944Sdim 783353944Sdimuptr GetRSS() { 784353944Sdim PROCESS_MEMORY_COUNTERS counters; 785353944Sdim if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) 786353944Sdim return 0; 787353944Sdim return counters.WorkingSetSize; 788353944Sdim} 789353944Sdim 790353944Sdimvoid *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } 791353944Sdimvoid internal_join_thread(void *th) { } 792353944Sdim 793353944Sdim// ---------------------- BlockingMutex ---------------- {{{1 794353944Sdim 795353944SdimBlockingMutex::BlockingMutex() { 796353944Sdim CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); 797353944Sdim internal_memset(this, 0, sizeof(*this)); 798353944Sdim} 799353944Sdim 800353944Sdimvoid BlockingMutex::Lock() { 801353944Sdim AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); 802353944Sdim CHECK_EQ(owner_, 0); 803353944Sdim owner_ = GetThreadSelf(); 804353944Sdim} 805353944Sdim 806353944Sdimvoid BlockingMutex::Unlock() { 807353944Sdim CheckLocked(); 808353944Sdim owner_ = 0; 809353944Sdim ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); 810353944Sdim} 811353944Sdim 812353944Sdimvoid BlockingMutex::CheckLocked() { 813353944Sdim CHECK_EQ(owner_, GetThreadSelf()); 814353944Sdim} 815353944Sdim 816353944Sdimuptr GetTlsSize() { 817353944Sdim return 0; 818353944Sdim} 819353944Sdim 820353944Sdimvoid InitTlsSize() { 821353944Sdim} 822353944Sdim 823353944Sdimvoid GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 824353944Sdim uptr *tls_addr, uptr *tls_size) { 825353944Sdim#if SANITIZER_GO 826353944Sdim *stk_addr = 0; 827353944Sdim *stk_size = 0; 828353944Sdim *tls_addr = 0; 829353944Sdim *tls_size = 0; 830353944Sdim#else 831353944Sdim uptr stack_top, stack_bottom; 832353944Sdim GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 833353944Sdim *stk_addr = stack_bottom; 834353944Sdim *stk_size = stack_top - stack_bottom; 835353944Sdim *tls_addr = 0; 836353944Sdim *tls_size = 0; 837353944Sdim#endif 838353944Sdim} 839353944Sdim 840353944Sdimvoid ReportFile::Write(const char *buffer, uptr length) { 841353944Sdim SpinMutexLock l(mu); 842353944Sdim ReopenIfNecessary(); 843353944Sdim if (!WriteToFile(fd, buffer, length)) { 844353944Sdim // stderr may be closed, but we may be able to print to the debugger 845353944Sdim // instead. This is the case when launching a program from Visual Studio, 846353944Sdim // and the following routine should write to its console. 847353944Sdim OutputDebugStringA(buffer); 848353944Sdim } 849353944Sdim} 850353944Sdim 851353944Sdimvoid SetAlternateSignalStack() { 852353944Sdim // FIXME: Decide what to do on Windows. 853353944Sdim} 854353944Sdim 855353944Sdimvoid UnsetAlternateSignalStack() { 856353944Sdim // FIXME: Decide what to do on Windows. 857353944Sdim} 858353944Sdim 859353944Sdimvoid InstallDeadlySignalHandlers(SignalHandlerType handler) { 860353944Sdim (void)handler; 861353944Sdim // FIXME: Decide what to do on Windows. 862353944Sdim} 863353944Sdim 864353944SdimHandleSignalMode GetHandleSignalMode(int signum) { 865353944Sdim // FIXME: Decide what to do on Windows. 866353944Sdim return kHandleSignalNo; 867353944Sdim} 868353944Sdim 869353944Sdim// Check based on flags if we should handle this exception. 870353944Sdimbool IsHandledDeadlyException(DWORD exceptionCode) { 871353944Sdim switch (exceptionCode) { 872353944Sdim case EXCEPTION_ACCESS_VIOLATION: 873353944Sdim case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 874353944Sdim case EXCEPTION_STACK_OVERFLOW: 875353944Sdim case EXCEPTION_DATATYPE_MISALIGNMENT: 876353944Sdim case EXCEPTION_IN_PAGE_ERROR: 877353944Sdim return common_flags()->handle_segv; 878353944Sdim case EXCEPTION_ILLEGAL_INSTRUCTION: 879353944Sdim case EXCEPTION_PRIV_INSTRUCTION: 880353944Sdim case EXCEPTION_BREAKPOINT: 881353944Sdim return common_flags()->handle_sigill; 882353944Sdim case EXCEPTION_FLT_DENORMAL_OPERAND: 883353944Sdim case EXCEPTION_FLT_DIVIDE_BY_ZERO: 884353944Sdim case EXCEPTION_FLT_INEXACT_RESULT: 885353944Sdim case EXCEPTION_FLT_INVALID_OPERATION: 886353944Sdim case EXCEPTION_FLT_OVERFLOW: 887353944Sdim case EXCEPTION_FLT_STACK_CHECK: 888353944Sdim case EXCEPTION_FLT_UNDERFLOW: 889353944Sdim case EXCEPTION_INT_DIVIDE_BY_ZERO: 890353944Sdim case EXCEPTION_INT_OVERFLOW: 891353944Sdim return common_flags()->handle_sigfpe; 892353944Sdim } 893353944Sdim return false; 894353944Sdim} 895353944Sdim 896353944Sdimbool IsAccessibleMemoryRange(uptr beg, uptr size) { 897353944Sdim SYSTEM_INFO si; 898353944Sdim GetNativeSystemInfo(&si); 899353944Sdim uptr page_size = si.dwPageSize; 900353944Sdim uptr page_mask = ~(page_size - 1); 901353944Sdim 902353944Sdim for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; 903353944Sdim page <= end;) { 904353944Sdim MEMORY_BASIC_INFORMATION info; 905353944Sdim if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) 906353944Sdim return false; 907353944Sdim 908353944Sdim if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || 909353944Sdim info.Protect == PAGE_EXECUTE) 910353944Sdim return false; 911353944Sdim 912353944Sdim if (info.RegionSize == 0) 913353944Sdim return false; 914353944Sdim 915353944Sdim page += info.RegionSize; 916353944Sdim } 917353944Sdim 918353944Sdim return true; 919353944Sdim} 920353944Sdim 921353944Sdimbool SignalContext::IsStackOverflow() const { 922353944Sdim return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; 923353944Sdim} 924353944Sdim 925353944Sdimvoid SignalContext::InitPcSpBp() { 926353944Sdim EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 927353944Sdim CONTEXT *context_record = (CONTEXT *)context; 928353944Sdim 929353944Sdim pc = (uptr)exception_record->ExceptionAddress; 930353944Sdim#ifdef _WIN64 931353944Sdim bp = (uptr)context_record->Rbp; 932353944Sdim sp = (uptr)context_record->Rsp; 933353944Sdim#else 934353944Sdim bp = (uptr)context_record->Ebp; 935353944Sdim sp = (uptr)context_record->Esp; 936353944Sdim#endif 937353944Sdim} 938353944Sdim 939353944Sdimuptr SignalContext::GetAddress() const { 940353944Sdim EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 941353944Sdim return exception_record->ExceptionInformation[1]; 942353944Sdim} 943353944Sdim 944353944Sdimbool SignalContext::IsMemoryAccess() const { 945353944Sdim return GetWriteFlag() != SignalContext::UNKNOWN; 946353944Sdim} 947353944Sdim 948353944Sdimbool SignalContext::IsTrueFaultingAddress() const { 949353944Sdim // FIXME: Provide real implementation for this. See Linux and Mac variants. 950353944Sdim return IsMemoryAccess(); 951353944Sdim} 952353944Sdim 953353944SdimSignalContext::WriteFlag SignalContext::GetWriteFlag() const { 954353944Sdim EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 955353944Sdim // The contents of this array are documented at 956353944Sdim // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx 957353944Sdim // The first element indicates read as 0, write as 1, or execute as 8. The 958353944Sdim // second element is the faulting address. 959353944Sdim switch (exception_record->ExceptionInformation[0]) { 960353944Sdim case 0: 961353944Sdim return SignalContext::READ; 962353944Sdim case 1: 963353944Sdim return SignalContext::WRITE; 964353944Sdim case 8: 965353944Sdim return SignalContext::UNKNOWN; 966353944Sdim } 967353944Sdim return SignalContext::UNKNOWN; 968353944Sdim} 969353944Sdim 970353944Sdimvoid SignalContext::DumpAllRegisters(void *context) { 971353944Sdim // FIXME: Implement this. 972353944Sdim} 973353944Sdim 974353944Sdimint SignalContext::GetType() const { 975353944Sdim return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode; 976353944Sdim} 977353944Sdim 978353944Sdimconst char *SignalContext::Describe() const { 979353944Sdim unsigned code = GetType(); 980353944Sdim // Get the string description of the exception if this is a known deadly 981353944Sdim // exception. 982353944Sdim switch (code) { 983353944Sdim case EXCEPTION_ACCESS_VIOLATION: 984353944Sdim return "access-violation"; 985353944Sdim case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 986353944Sdim return "array-bounds-exceeded"; 987353944Sdim case EXCEPTION_STACK_OVERFLOW: 988353944Sdim return "stack-overflow"; 989353944Sdim case EXCEPTION_DATATYPE_MISALIGNMENT: 990353944Sdim return "datatype-misalignment"; 991353944Sdim case EXCEPTION_IN_PAGE_ERROR: 992353944Sdim return "in-page-error"; 993353944Sdim case EXCEPTION_ILLEGAL_INSTRUCTION: 994353944Sdim return "illegal-instruction"; 995353944Sdim case EXCEPTION_PRIV_INSTRUCTION: 996353944Sdim return "priv-instruction"; 997353944Sdim case EXCEPTION_BREAKPOINT: 998353944Sdim return "breakpoint"; 999353944Sdim case EXCEPTION_FLT_DENORMAL_OPERAND: 1000353944Sdim return "flt-denormal-operand"; 1001353944Sdim case EXCEPTION_FLT_DIVIDE_BY_ZERO: 1002353944Sdim return "flt-divide-by-zero"; 1003353944Sdim case EXCEPTION_FLT_INEXACT_RESULT: 1004353944Sdim return "flt-inexact-result"; 1005353944Sdim case EXCEPTION_FLT_INVALID_OPERATION: 1006353944Sdim return "flt-invalid-operation"; 1007353944Sdim case EXCEPTION_FLT_OVERFLOW: 1008353944Sdim return "flt-overflow"; 1009353944Sdim case EXCEPTION_FLT_STACK_CHECK: 1010353944Sdim return "flt-stack-check"; 1011353944Sdim case EXCEPTION_FLT_UNDERFLOW: 1012353944Sdim return "flt-underflow"; 1013353944Sdim case EXCEPTION_INT_DIVIDE_BY_ZERO: 1014353944Sdim return "int-divide-by-zero"; 1015353944Sdim case EXCEPTION_INT_OVERFLOW: 1016353944Sdim return "int-overflow"; 1017353944Sdim } 1018353944Sdim return "unknown exception"; 1019353944Sdim} 1020353944Sdim 1021353944Sdimuptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 1022353944Sdim // FIXME: Actually implement this function. 1023353944Sdim CHECK_GT(buf_len, 0); 1024353944Sdim buf[0] = 0; 1025353944Sdim return 0; 1026353944Sdim} 1027353944Sdim 1028353944Sdimuptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { 1029353944Sdim return ReadBinaryName(buf, buf_len); 1030353944Sdim} 1031353944Sdim 1032353944Sdimvoid CheckVMASize() { 1033353944Sdim // Do nothing. 1034353944Sdim} 1035353944Sdim 1036353944Sdimvoid InitializePlatformEarly() { 1037353944Sdim // Do nothing. 1038353944Sdim} 1039353944Sdim 1040353944Sdimvoid MaybeReexec() { 1041353944Sdim // No need to re-exec on Windows. 1042353944Sdim} 1043353944Sdim 1044353944Sdimvoid CheckASLR() { 1045353944Sdim // Do nothing 1046353944Sdim} 1047353944Sdim 1048353944Sdimvoid CheckMPROTECT() { 1049353944Sdim // Do nothing 1050353944Sdim} 1051353944Sdim 1052353944Sdimchar **GetArgv() { 1053353944Sdim // FIXME: Actually implement this function. 1054353944Sdim return 0; 1055353944Sdim} 1056353944Sdim 1057353944Sdimchar **GetEnviron() { 1058353944Sdim // FIXME: Actually implement this function. 1059353944Sdim return 0; 1060353944Sdim} 1061353944Sdim 1062353944Sdimpid_t StartSubprocess(const char *program, const char *const argv[], 1063353944Sdim fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { 1064353944Sdim // FIXME: implement on this platform 1065353944Sdim // Should be implemented based on 1066353944Sdim // SymbolizerProcess::StarAtSymbolizerSubprocess 1067353944Sdim // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. 1068353944Sdim return -1; 1069353944Sdim} 1070353944Sdim 1071353944Sdimbool IsProcessRunning(pid_t pid) { 1072353944Sdim // FIXME: implement on this platform. 1073353944Sdim return false; 1074353944Sdim} 1075353944Sdim 1076353944Sdimint WaitForProcess(pid_t pid) { return -1; } 1077353944Sdim 1078353944Sdim// FIXME implement on this platform. 1079353944Sdimvoid GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } 1080353944Sdim 1081353944Sdimvoid CheckNoDeepBind(const char *filename, int flag) { 1082353944Sdim // Do nothing. 1083353944Sdim} 1084353944Sdim 1085353944Sdim// FIXME: implement on this platform. 1086353944Sdimbool GetRandom(void *buffer, uptr length, bool blocking) { 1087353944Sdim UNIMPLEMENTED(); 1088353944Sdim} 1089353944Sdim 1090353944Sdimu32 GetNumberOfCPUs() { 1091353944Sdim SYSTEM_INFO sysinfo = {}; 1092353944Sdim GetNativeSystemInfo(&sysinfo); 1093353944Sdim return sysinfo.dwNumberOfProcessors; 1094353944Sdim} 1095353944Sdim 1096353944Sdim#if SANITIZER_WIN_TRACE 1097353944Sdim// TODO(mcgov): Rename this project-wide to PlatformLogInit 1098353944Sdimvoid AndroidLogInit(void) { 1099353944Sdim HRESULT hr = TraceLoggingRegister(g_asan_provider); 1100353944Sdim if (!SUCCEEDED(hr)) 1101353944Sdim return; 1102353944Sdim} 1103353944Sdim 1104353944Sdimvoid SetAbortMessage(const char *) {} 1105353944Sdim 1106353944Sdimvoid LogFullErrorReport(const char *buffer) { 1107353944Sdim if (common_flags()->log_to_syslog) { 1108353944Sdim InternalMmapVector<wchar_t> filename; 1109353944Sdim DWORD filename_length = 0; 1110353944Sdim do { 1111353944Sdim filename.resize(filename.size() + 0x100); 1112353944Sdim filename_length = 1113353944Sdim GetModuleFileNameW(NULL, filename.begin(), filename.size()); 1114353944Sdim } while (filename_length >= filename.size()); 1115353944Sdim TraceLoggingWrite(g_asan_provider, "AsanReportEvent", 1116353944Sdim TraceLoggingValue(filename.begin(), "ExecutableName"), 1117353944Sdim TraceLoggingValue(buffer, "AsanReportContents")); 1118353944Sdim } 1119353944Sdim} 1120353944Sdim#endif // SANITIZER_WIN_TRACE 1121353944Sdim 1122353944Sdim} // namespace __sanitizer 1123353944Sdim 1124353944Sdim#endif // _WIN32 1125