168d75effSDimitry Andric //===-- sanitizer_win.cpp -------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries and implements windows-specific functions from 1168d75effSDimitry Andric // sanitizer_libc.h. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "sanitizer_platform.h" 1568d75effSDimitry Andric #if SANITIZER_WINDOWS 1668d75effSDimitry Andric 1768d75effSDimitry Andric #define WIN32_LEAN_AND_MEAN 1868d75effSDimitry Andric #define NOGDI 1968d75effSDimitry Andric #include <windows.h> 2068d75effSDimitry Andric #include <io.h> 2168d75effSDimitry Andric #include <psapi.h> 2268d75effSDimitry Andric #include <stdlib.h> 2368d75effSDimitry Andric 2468d75effSDimitry Andric #include "sanitizer_common.h" 2568d75effSDimitry Andric #include "sanitizer_file.h" 2668d75effSDimitry Andric #include "sanitizer_libc.h" 2768d75effSDimitry Andric #include "sanitizer_mutex.h" 2868d75effSDimitry Andric #include "sanitizer_placement_new.h" 2968d75effSDimitry Andric #include "sanitizer_win_defs.h" 3068d75effSDimitry Andric 3168d75effSDimitry Andric #if defined(PSAPI_VERSION) && PSAPI_VERSION == 1 3268d75effSDimitry Andric #pragma comment(lib, "psapi") 3368d75effSDimitry Andric #endif 3468d75effSDimitry Andric #if SANITIZER_WIN_TRACE 3568d75effSDimitry Andric #include <traceloggingprovider.h> 3668d75effSDimitry Andric // Windows trace logging provider init 3768d75effSDimitry Andric #pragma comment(lib, "advapi32.lib") 3868d75effSDimitry Andric TRACELOGGING_DECLARE_PROVIDER(g_asan_provider); 3968d75effSDimitry Andric // GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp 4068d75effSDimitry Andric TRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider", 4168d75effSDimitry Andric (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b, 4268d75effSDimitry Andric 0x53, 0x0b, 0xd0, 0xf3, 0xfa)); 4368d75effSDimitry Andric #else 4468d75effSDimitry Andric #define TraceLoggingUnregister(x) 4568d75effSDimitry Andric #endif 4668d75effSDimitry Andric 47*fe6060f1SDimitry Andric // For WaitOnAddress 48*fe6060f1SDimitry Andric # pragma comment(lib, "synchronization.lib") 49*fe6060f1SDimitry Andric 5068d75effSDimitry Andric // A macro to tell the compiler that this part of the code cannot be reached, 5168d75effSDimitry Andric // if the compiler supports this feature. Since we're using this in 5268d75effSDimitry Andric // code that is called when terminating the process, the expansion of the 5368d75effSDimitry Andric // macro should not terminate the process to avoid infinite recursion. 5468d75effSDimitry Andric #if defined(__clang__) 5568d75effSDimitry Andric # define BUILTIN_UNREACHABLE() __builtin_unreachable() 5668d75effSDimitry Andric #elif defined(__GNUC__) && \ 5768d75effSDimitry Andric (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) 5868d75effSDimitry Andric # define BUILTIN_UNREACHABLE() __builtin_unreachable() 5968d75effSDimitry Andric #elif defined(_MSC_VER) 6068d75effSDimitry Andric # define BUILTIN_UNREACHABLE() __assume(0) 6168d75effSDimitry Andric #else 6268d75effSDimitry Andric # define BUILTIN_UNREACHABLE() 6368d75effSDimitry Andric #endif 6468d75effSDimitry Andric 6568d75effSDimitry Andric namespace __sanitizer { 6668d75effSDimitry Andric 6768d75effSDimitry Andric #include "sanitizer_syscall_generic.inc" 6868d75effSDimitry Andric 6968d75effSDimitry Andric // --------------------- sanitizer_common.h 7068d75effSDimitry Andric uptr GetPageSize() { 7168d75effSDimitry Andric SYSTEM_INFO si; 7268d75effSDimitry Andric GetSystemInfo(&si); 7368d75effSDimitry Andric return si.dwPageSize; 7468d75effSDimitry Andric } 7568d75effSDimitry Andric 7668d75effSDimitry Andric uptr GetMmapGranularity() { 7768d75effSDimitry Andric SYSTEM_INFO si; 7868d75effSDimitry Andric GetSystemInfo(&si); 7968d75effSDimitry Andric return si.dwAllocationGranularity; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric 8268d75effSDimitry Andric uptr GetMaxUserVirtualAddress() { 8368d75effSDimitry Andric SYSTEM_INFO si; 8468d75effSDimitry Andric GetSystemInfo(&si); 8568d75effSDimitry Andric return (uptr)si.lpMaximumApplicationAddress; 8668d75effSDimitry Andric } 8768d75effSDimitry Andric 8868d75effSDimitry Andric uptr GetMaxVirtualAddress() { 8968d75effSDimitry Andric return GetMaxUserVirtualAddress(); 9068d75effSDimitry Andric } 9168d75effSDimitry Andric 9268d75effSDimitry Andric bool FileExists(const char *filename) { 9368d75effSDimitry Andric return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; 9468d75effSDimitry Andric } 9568d75effSDimitry Andric 9668d75effSDimitry Andric uptr internal_getpid() { 9768d75effSDimitry Andric return GetProcessId(GetCurrentProcess()); 9868d75effSDimitry Andric } 9968d75effSDimitry Andric 1005ffd83dbSDimitry Andric int internal_dlinfo(void *handle, int request, void *p) { 1015ffd83dbSDimitry Andric UNIMPLEMENTED(); 1025ffd83dbSDimitry Andric } 1035ffd83dbSDimitry Andric 10468d75effSDimitry Andric // In contrast to POSIX, on Windows GetCurrentThreadId() 10568d75effSDimitry Andric // returns a system-unique identifier. 10668d75effSDimitry Andric tid_t GetTid() { 10768d75effSDimitry Andric return GetCurrentThreadId(); 10868d75effSDimitry Andric } 10968d75effSDimitry Andric 11068d75effSDimitry Andric uptr GetThreadSelf() { 11168d75effSDimitry Andric return GetTid(); 11268d75effSDimitry Andric } 11368d75effSDimitry Andric 11468d75effSDimitry Andric #if !SANITIZER_GO 11568d75effSDimitry Andric void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 11668d75effSDimitry Andric uptr *stack_bottom) { 11768d75effSDimitry Andric CHECK(stack_top); 11868d75effSDimitry Andric CHECK(stack_bottom); 11968d75effSDimitry Andric MEMORY_BASIC_INFORMATION mbi; 12068d75effSDimitry Andric CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); 12168d75effSDimitry Andric // FIXME: is it possible for the stack to not be a single allocation? 12268d75effSDimitry Andric // Are these values what ASan expects to get (reserved, not committed; 12368d75effSDimitry Andric // including stack guard page) ? 12468d75effSDimitry Andric *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; 12568d75effSDimitry Andric *stack_bottom = (uptr)mbi.AllocationBase; 12668d75effSDimitry Andric } 12768d75effSDimitry Andric #endif // #if !SANITIZER_GO 12868d75effSDimitry Andric 12968d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { 13068d75effSDimitry Andric void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 13168d75effSDimitry Andric if (rv == 0) 13268d75effSDimitry Andric ReportMmapFailureAndDie(size, mem_type, "allocate", 13368d75effSDimitry Andric GetLastError(), raw_report); 13468d75effSDimitry Andric return rv; 13568d75effSDimitry Andric } 13668d75effSDimitry Andric 13768d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) { 13868d75effSDimitry Andric if (!size || !addr) 13968d75effSDimitry Andric return; 14068d75effSDimitry Andric 14168d75effSDimitry Andric MEMORY_BASIC_INFORMATION mbi; 14268d75effSDimitry Andric CHECK(VirtualQuery(addr, &mbi, sizeof(mbi))); 14368d75effSDimitry Andric 14468d75effSDimitry Andric // MEM_RELEASE can only be used to unmap whole regions previously mapped with 14568d75effSDimitry Andric // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that 14668d75effSDimitry Andric // fails try MEM_DECOMMIT. 14768d75effSDimitry Andric if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { 14868d75effSDimitry Andric if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 14968d75effSDimitry Andric Report("ERROR: %s failed to " 15068d75effSDimitry Andric "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", 15168d75effSDimitry Andric SanitizerToolName, size, size, addr, GetLastError()); 15268d75effSDimitry Andric CHECK("unable to unmap" && 0); 15368d75effSDimitry Andric } 15468d75effSDimitry Andric } 15568d75effSDimitry Andric } 15668d75effSDimitry Andric 15768d75effSDimitry Andric static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, 15868d75effSDimitry Andric const char *mmap_type) { 15968d75effSDimitry Andric error_t last_error = GetLastError(); 16068d75effSDimitry Andric if (last_error == ERROR_NOT_ENOUGH_MEMORY) 16168d75effSDimitry Andric return nullptr; 16268d75effSDimitry Andric ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); 16368d75effSDimitry Andric } 16468d75effSDimitry Andric 16568d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { 16668d75effSDimitry Andric void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 16768d75effSDimitry Andric if (rv == 0) 16868d75effSDimitry Andric return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); 16968d75effSDimitry Andric return rv; 17068d75effSDimitry Andric } 17168d75effSDimitry Andric 17268d75effSDimitry Andric // We want to map a chunk of address space aligned to 'alignment'. 17368d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, 17468d75effSDimitry Andric const char *mem_type) { 17568d75effSDimitry Andric CHECK(IsPowerOfTwo(size)); 17668d75effSDimitry Andric CHECK(IsPowerOfTwo(alignment)); 17768d75effSDimitry Andric 17868d75effSDimitry Andric // Windows will align our allocations to at least 64K. 17968d75effSDimitry Andric alignment = Max(alignment, GetMmapGranularity()); 18068d75effSDimitry Andric 18168d75effSDimitry Andric uptr mapped_addr = 18268d75effSDimitry Andric (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 18368d75effSDimitry Andric if (!mapped_addr) 18468d75effSDimitry Andric return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 18568d75effSDimitry Andric 18668d75effSDimitry Andric // If we got it right on the first try, return. Otherwise, unmap it and go to 18768d75effSDimitry Andric // the slow path. 18868d75effSDimitry Andric if (IsAligned(mapped_addr, alignment)) 18968d75effSDimitry Andric return (void*)mapped_addr; 19068d75effSDimitry Andric if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) 19168d75effSDimitry Andric ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); 19268d75effSDimitry Andric 19368d75effSDimitry Andric // If we didn't get an aligned address, overallocate, find an aligned address, 19468d75effSDimitry Andric // unmap, and try to allocate at that aligned address. 19568d75effSDimitry Andric int retries = 0; 19668d75effSDimitry Andric const int kMaxRetries = 10; 19768d75effSDimitry Andric for (; retries < kMaxRetries && 19868d75effSDimitry Andric (mapped_addr == 0 || !IsAligned(mapped_addr, alignment)); 19968d75effSDimitry Andric retries++) { 20068d75effSDimitry Andric // Overallocate size + alignment bytes. 20168d75effSDimitry Andric mapped_addr = 20268d75effSDimitry Andric (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); 20368d75effSDimitry Andric if (!mapped_addr) 20468d75effSDimitry Andric return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 20568d75effSDimitry Andric 20668d75effSDimitry Andric // Find the aligned address. 20768d75effSDimitry Andric uptr aligned_addr = RoundUpTo(mapped_addr, alignment); 20868d75effSDimitry Andric 20968d75effSDimitry Andric // Free the overallocation. 21068d75effSDimitry Andric if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0) 21168d75effSDimitry Andric ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError()); 21268d75effSDimitry Andric 21368d75effSDimitry Andric // Attempt to allocate exactly the number of bytes we need at the aligned 21468d75effSDimitry Andric // address. This may fail for a number of reasons, in which case we continue 21568d75effSDimitry Andric // the loop. 21668d75effSDimitry Andric mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size, 21768d75effSDimitry Andric MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 21868d75effSDimitry Andric } 21968d75effSDimitry Andric 22068d75effSDimitry Andric // Fail if we can't make this work quickly. 22168d75effSDimitry Andric if (retries == kMaxRetries && mapped_addr == 0) 22268d75effSDimitry Andric return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); 22368d75effSDimitry Andric 22468d75effSDimitry Andric return (void *)mapped_addr; 22568d75effSDimitry Andric } 22668d75effSDimitry Andric 22768d75effSDimitry Andric bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { 22868d75effSDimitry Andric // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 22968d75effSDimitry Andric // but on Win64 it does. 23068d75effSDimitry Andric (void)name; // unsupported 23168d75effSDimitry Andric #if !SANITIZER_GO && SANITIZER_WINDOWS64 23268d75effSDimitry Andric // On asan/Windows64, use MEM_COMMIT would result in error 23368d75effSDimitry Andric // 1455:ERROR_COMMITMENT_LIMIT. 23468d75effSDimitry Andric // Asan uses exception handler to commit page on demand. 23568d75effSDimitry Andric void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE); 23668d75effSDimitry Andric #else 23768d75effSDimitry Andric void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, 23868d75effSDimitry Andric PAGE_READWRITE); 23968d75effSDimitry Andric #endif 24068d75effSDimitry Andric if (p == 0) { 24168d75effSDimitry Andric Report("ERROR: %s failed to " 24268d75effSDimitry Andric "allocate %p (%zd) bytes at %p (error code: %d)\n", 24368d75effSDimitry Andric SanitizerToolName, size, size, fixed_addr, GetLastError()); 24468d75effSDimitry Andric return false; 24568d75effSDimitry Andric } 24668d75effSDimitry Andric return true; 24768d75effSDimitry Andric } 24868d75effSDimitry Andric 24968d75effSDimitry Andric bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { 25068d75effSDimitry Andric // FIXME: Windows support large pages too. Might be worth checking 25168d75effSDimitry Andric return MmapFixedNoReserve(fixed_addr, size, name); 25268d75effSDimitry Andric } 25368d75effSDimitry Andric 25468d75effSDimitry Andric // Memory space mapped by 'MmapFixedOrDie' must have been reserved by 25568d75effSDimitry Andric // 'MmapFixedNoAccess'. 25668d75effSDimitry Andric void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { 25768d75effSDimitry Andric void *p = VirtualAlloc((LPVOID)fixed_addr, size, 25868d75effSDimitry Andric MEM_COMMIT, PAGE_READWRITE); 25968d75effSDimitry Andric if (p == 0) { 26068d75effSDimitry Andric char mem_type[30]; 26168d75effSDimitry Andric internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 26268d75effSDimitry Andric fixed_addr); 26368d75effSDimitry Andric ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError()); 26468d75effSDimitry Andric } 26568d75effSDimitry Andric return p; 26668d75effSDimitry Andric } 26768d75effSDimitry Andric 26868d75effSDimitry Andric // Uses fixed_addr for now. 26968d75effSDimitry Andric // Will use offset instead once we've implemented this function for real. 27068d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { 27168d75effSDimitry Andric return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size)); 27268d75effSDimitry Andric } 27368d75effSDimitry Andric 27468d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, 27568d75effSDimitry Andric const char *name) { 27668d75effSDimitry Andric return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size)); 27768d75effSDimitry Andric } 27868d75effSDimitry Andric 27968d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) { 28068d75effSDimitry Andric // Only unmap if it covers the entire range. 28168d75effSDimitry Andric CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_)); 28268d75effSDimitry Andric // We unmap the whole range, just null out the base. 28368d75effSDimitry Andric base_ = nullptr; 28468d75effSDimitry Andric size_ = 0; 28568d75effSDimitry Andric UnmapOrDie(reinterpret_cast<void*>(addr), size); 28668d75effSDimitry Andric } 28768d75effSDimitry Andric 28868d75effSDimitry Andric void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { 28968d75effSDimitry Andric void *p = VirtualAlloc((LPVOID)fixed_addr, size, 29068d75effSDimitry Andric MEM_COMMIT, PAGE_READWRITE); 29168d75effSDimitry Andric if (p == 0) { 29268d75effSDimitry Andric char mem_type[30]; 29368d75effSDimitry Andric internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 29468d75effSDimitry Andric fixed_addr); 29568d75effSDimitry Andric return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); 29668d75effSDimitry Andric } 29768d75effSDimitry Andric return p; 29868d75effSDimitry Andric } 29968d75effSDimitry Andric 30068d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 30168d75effSDimitry Andric // FIXME: make this really NoReserve? 30268d75effSDimitry Andric return MmapOrDie(size, mem_type); 30368d75effSDimitry Andric } 30468d75effSDimitry Andric 30568d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { 30668d75effSDimitry Andric base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size); 30768d75effSDimitry Andric size_ = size; 30868d75effSDimitry Andric name_ = name; 30968d75effSDimitry Andric (void)os_handle_; // unsupported 31068d75effSDimitry Andric return reinterpret_cast<uptr>(base_); 31168d75effSDimitry Andric } 31268d75effSDimitry Andric 31368d75effSDimitry Andric 31468d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { 31568d75effSDimitry Andric (void)name; // unsupported 31668d75effSDimitry Andric void *res = VirtualAlloc((LPVOID)fixed_addr, size, 31768d75effSDimitry Andric MEM_RESERVE, PAGE_NOACCESS); 31868d75effSDimitry Andric if (res == 0) 31968d75effSDimitry Andric Report("WARNING: %s failed to " 32068d75effSDimitry Andric "mprotect %p (%zd) bytes at %p (error code: %d)\n", 32168d75effSDimitry Andric SanitizerToolName, size, size, fixed_addr, GetLastError()); 32268d75effSDimitry Andric return res; 32368d75effSDimitry Andric } 32468d75effSDimitry Andric 32568d75effSDimitry Andric void *MmapNoAccess(uptr size) { 32668d75effSDimitry Andric void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); 32768d75effSDimitry Andric if (res == 0) 32868d75effSDimitry Andric Report("WARNING: %s failed to " 32968d75effSDimitry Andric "mprotect %p (%zd) bytes (error code: %d)\n", 33068d75effSDimitry Andric SanitizerToolName, size, size, GetLastError()); 33168d75effSDimitry Andric return res; 33268d75effSDimitry Andric } 33368d75effSDimitry Andric 33468d75effSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) { 33568d75effSDimitry Andric DWORD old_protection; 33668d75effSDimitry Andric return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); 33768d75effSDimitry Andric } 33868d75effSDimitry Andric 33968d75effSDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) { 340*fe6060f1SDimitry Andric uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()), 341*fe6060f1SDimitry Andric end_aligned = RoundDownTo(end, GetPageSizeCached()); 342*fe6060f1SDimitry Andric CHECK(beg < end); // make sure the region is sane 343*fe6060f1SDimitry Andric if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page; 344*fe6060f1SDimitry Andric return; 345*fe6060f1SDimitry Andric UnmapOrDie((void *)beg, end_aligned - beg_aligned); 34668d75effSDimitry Andric } 34768d75effSDimitry Andric 34868d75effSDimitry Andric void SetShadowRegionHugePageMode(uptr addr, uptr size) { 34968d75effSDimitry Andric // FIXME: probably similar to ReleaseMemoryToOS. 35068d75effSDimitry Andric } 35168d75effSDimitry Andric 35268d75effSDimitry Andric bool DontDumpShadowMemory(uptr addr, uptr length) { 35368d75effSDimitry Andric // This is almost useless on 32-bits. 35468d75effSDimitry Andric // FIXME: add madvise-analog when we move to 64-bits. 35568d75effSDimitry Andric return true; 35668d75effSDimitry Andric } 35768d75effSDimitry Andric 358e8d8bef9SDimitry Andric uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, 359e8d8bef9SDimitry Andric uptr min_shadow_base_alignment, 360e8d8bef9SDimitry Andric UNUSED uptr &high_mem_end) { 361e8d8bef9SDimitry Andric const uptr granularity = GetMmapGranularity(); 362e8d8bef9SDimitry Andric const uptr alignment = 363e8d8bef9SDimitry Andric Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); 364e8d8bef9SDimitry Andric const uptr left_padding = 365e8d8bef9SDimitry Andric Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); 366e8d8bef9SDimitry Andric uptr space_size = shadow_size_bytes + left_padding; 367e8d8bef9SDimitry Andric uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, 368e8d8bef9SDimitry Andric granularity, nullptr, nullptr); 369e8d8bef9SDimitry Andric CHECK_NE((uptr)0, shadow_start); 370e8d8bef9SDimitry Andric CHECK(IsAligned(shadow_start, alignment)); 371e8d8bef9SDimitry Andric return shadow_start; 372e8d8bef9SDimitry Andric } 373e8d8bef9SDimitry Andric 37468d75effSDimitry Andric uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, 37568d75effSDimitry Andric uptr *largest_gap_found, 37668d75effSDimitry Andric uptr *max_occupied_addr) { 37768d75effSDimitry Andric uptr address = 0; 37868d75effSDimitry Andric while (true) { 37968d75effSDimitry Andric MEMORY_BASIC_INFORMATION info; 38068d75effSDimitry Andric if (!::VirtualQuery((void*)address, &info, sizeof(info))) 38168d75effSDimitry Andric return 0; 38268d75effSDimitry Andric 38368d75effSDimitry Andric if (info.State == MEM_FREE) { 38468d75effSDimitry Andric uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, 38568d75effSDimitry Andric alignment); 38668d75effSDimitry Andric if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) 38768d75effSDimitry Andric return shadow_address; 38868d75effSDimitry Andric } 38968d75effSDimitry Andric 39068d75effSDimitry Andric // Move to the next region. 39168d75effSDimitry Andric address = (uptr)info.BaseAddress + info.RegionSize; 39268d75effSDimitry Andric } 39368d75effSDimitry Andric return 0; 39468d75effSDimitry Andric } 39568d75effSDimitry Andric 396*fe6060f1SDimitry Andric uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, 397*fe6060f1SDimitry Andric uptr num_aliases, uptr ring_buffer_size) { 398*fe6060f1SDimitry Andric CHECK(false && "HWASan aliasing is unimplemented on Windows"); 399*fe6060f1SDimitry Andric return 0; 400*fe6060f1SDimitry Andric } 401*fe6060f1SDimitry Andric 40268d75effSDimitry Andric bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 40368d75effSDimitry Andric MEMORY_BASIC_INFORMATION mbi; 40468d75effSDimitry Andric CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); 40568d75effSDimitry Andric return mbi.Protect == PAGE_NOACCESS && 40668d75effSDimitry Andric (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; 40768d75effSDimitry Andric } 40868d75effSDimitry Andric 40968d75effSDimitry Andric void *MapFileToMemory(const char *file_name, uptr *buff_size) { 41068d75effSDimitry Andric UNIMPLEMENTED(); 41168d75effSDimitry Andric } 41268d75effSDimitry Andric 41368d75effSDimitry Andric void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 41468d75effSDimitry Andric UNIMPLEMENTED(); 41568d75effSDimitry Andric } 41668d75effSDimitry Andric 41768d75effSDimitry Andric static const int kMaxEnvNameLength = 128; 41868d75effSDimitry Andric static const DWORD kMaxEnvValueLength = 32767; 41968d75effSDimitry Andric 42068d75effSDimitry Andric namespace { 42168d75effSDimitry Andric 42268d75effSDimitry Andric struct EnvVariable { 42368d75effSDimitry Andric char name[kMaxEnvNameLength]; 42468d75effSDimitry Andric char value[kMaxEnvValueLength]; 42568d75effSDimitry Andric }; 42668d75effSDimitry Andric 42768d75effSDimitry Andric } // namespace 42868d75effSDimitry Andric 42968d75effSDimitry Andric static const int kEnvVariables = 5; 43068d75effSDimitry Andric static EnvVariable env_vars[kEnvVariables]; 43168d75effSDimitry Andric static int num_env_vars; 43268d75effSDimitry Andric 43368d75effSDimitry Andric const char *GetEnv(const char *name) { 43468d75effSDimitry Andric // Note: this implementation caches the values of the environment variables 43568d75effSDimitry Andric // and limits their quantity. 43668d75effSDimitry Andric for (int i = 0; i < num_env_vars; i++) { 43768d75effSDimitry Andric if (0 == internal_strcmp(name, env_vars[i].name)) 43868d75effSDimitry Andric return env_vars[i].value; 43968d75effSDimitry Andric } 44068d75effSDimitry Andric CHECK_LT(num_env_vars, kEnvVariables); 44168d75effSDimitry Andric DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 44268d75effSDimitry Andric kMaxEnvValueLength); 44368d75effSDimitry Andric if (rv > 0 && rv < kMaxEnvValueLength) { 44468d75effSDimitry Andric CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 44568d75effSDimitry Andric internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 44668d75effSDimitry Andric num_env_vars++; 44768d75effSDimitry Andric return env_vars[num_env_vars - 1].value; 44868d75effSDimitry Andric } 44968d75effSDimitry Andric return 0; 45068d75effSDimitry Andric } 45168d75effSDimitry Andric 45268d75effSDimitry Andric const char *GetPwd() { 45368d75effSDimitry Andric UNIMPLEMENTED(); 45468d75effSDimitry Andric } 45568d75effSDimitry Andric 45668d75effSDimitry Andric u32 GetUid() { 45768d75effSDimitry Andric UNIMPLEMENTED(); 45868d75effSDimitry Andric } 45968d75effSDimitry Andric 46068d75effSDimitry Andric namespace { 46168d75effSDimitry Andric struct ModuleInfo { 46268d75effSDimitry Andric const char *filepath; 46368d75effSDimitry Andric uptr base_address; 46468d75effSDimitry Andric uptr end_address; 46568d75effSDimitry Andric }; 46668d75effSDimitry Andric 46768d75effSDimitry Andric #if !SANITIZER_GO 46868d75effSDimitry Andric int CompareModulesBase(const void *pl, const void *pr) { 46968d75effSDimitry Andric const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; 47068d75effSDimitry Andric if (l->base_address < r->base_address) 47168d75effSDimitry Andric return -1; 47268d75effSDimitry Andric return l->base_address > r->base_address; 47368d75effSDimitry Andric } 47468d75effSDimitry Andric #endif 47568d75effSDimitry Andric } // namespace 47668d75effSDimitry Andric 47768d75effSDimitry Andric #if !SANITIZER_GO 47868d75effSDimitry Andric void DumpProcessMap() { 47968d75effSDimitry Andric Report("Dumping process modules:\n"); 48068d75effSDimitry Andric ListOfModules modules; 48168d75effSDimitry Andric modules.init(); 48268d75effSDimitry Andric uptr num_modules = modules.size(); 48368d75effSDimitry Andric 48468d75effSDimitry Andric InternalMmapVector<ModuleInfo> module_infos(num_modules); 48568d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 48668d75effSDimitry Andric module_infos[i].filepath = modules[i].full_name(); 48768d75effSDimitry Andric module_infos[i].base_address = modules[i].ranges().front()->beg; 48868d75effSDimitry Andric module_infos[i].end_address = modules[i].ranges().back()->end; 48968d75effSDimitry Andric } 49068d75effSDimitry Andric qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), 49168d75effSDimitry Andric CompareModulesBase); 49268d75effSDimitry Andric 49368d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 49468d75effSDimitry Andric const ModuleInfo &mi = module_infos[i]; 49568d75effSDimitry Andric if (mi.end_address != 0) { 49668d75effSDimitry Andric Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, 49768d75effSDimitry Andric mi.filepath[0] ? mi.filepath : "[no name]"); 49868d75effSDimitry Andric } else if (mi.filepath[0]) { 49968d75effSDimitry Andric Printf("\t??\?-??? %s\n", mi.filepath); 50068d75effSDimitry Andric } else { 50168d75effSDimitry Andric Printf("\t???\n"); 50268d75effSDimitry Andric } 50368d75effSDimitry Andric } 50468d75effSDimitry Andric } 50568d75effSDimitry Andric #endif 50668d75effSDimitry Andric 50768d75effSDimitry Andric void DisableCoreDumperIfNecessary() { 50868d75effSDimitry Andric // Do nothing. 50968d75effSDimitry Andric } 51068d75effSDimitry Andric 51168d75effSDimitry Andric void ReExec() { 51268d75effSDimitry Andric UNIMPLEMENTED(); 51368d75effSDimitry Andric } 51468d75effSDimitry Andric 51568d75effSDimitry Andric void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} 51668d75effSDimitry Andric 51768d75effSDimitry Andric bool StackSizeIsUnlimited() { 51868d75effSDimitry Andric UNIMPLEMENTED(); 51968d75effSDimitry Andric } 52068d75effSDimitry Andric 52168d75effSDimitry Andric void SetStackSizeLimitInBytes(uptr limit) { 52268d75effSDimitry Andric UNIMPLEMENTED(); 52368d75effSDimitry Andric } 52468d75effSDimitry Andric 52568d75effSDimitry Andric bool AddressSpaceIsUnlimited() { 52668d75effSDimitry Andric UNIMPLEMENTED(); 52768d75effSDimitry Andric } 52868d75effSDimitry Andric 52968d75effSDimitry Andric void SetAddressSpaceUnlimited() { 53068d75effSDimitry Andric UNIMPLEMENTED(); 53168d75effSDimitry Andric } 53268d75effSDimitry Andric 53368d75effSDimitry Andric bool IsPathSeparator(const char c) { 53468d75effSDimitry Andric return c == '\\' || c == '/'; 53568d75effSDimitry Andric } 53668d75effSDimitry Andric 53768d75effSDimitry Andric static bool IsAlpha(char c) { 53868d75effSDimitry Andric c = ToLower(c); 53968d75effSDimitry Andric return c >= 'a' && c <= 'z'; 54068d75effSDimitry Andric } 54168d75effSDimitry Andric 54268d75effSDimitry Andric bool IsAbsolutePath(const char *path) { 54368d75effSDimitry Andric return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && 54468d75effSDimitry Andric IsPathSeparator(path[2]); 54568d75effSDimitry Andric } 54668d75effSDimitry Andric 547*fe6060f1SDimitry Andric void internal_usleep(u64 useconds) { Sleep(useconds / 1000); } 54868d75effSDimitry Andric 54968d75effSDimitry Andric u64 NanoTime() { 55068d75effSDimitry Andric static LARGE_INTEGER frequency = {}; 55168d75effSDimitry Andric LARGE_INTEGER counter; 55268d75effSDimitry Andric if (UNLIKELY(frequency.QuadPart == 0)) { 55368d75effSDimitry Andric QueryPerformanceFrequency(&frequency); 55468d75effSDimitry Andric CHECK_NE(frequency.QuadPart, 0); 55568d75effSDimitry Andric } 55668d75effSDimitry Andric QueryPerformanceCounter(&counter); 55768d75effSDimitry Andric counter.QuadPart *= 1000ULL * 1000000ULL; 55868d75effSDimitry Andric counter.QuadPart /= frequency.QuadPart; 55968d75effSDimitry Andric return counter.QuadPart; 56068d75effSDimitry Andric } 56168d75effSDimitry Andric 56268d75effSDimitry Andric u64 MonotonicNanoTime() { return NanoTime(); } 56368d75effSDimitry Andric 56468d75effSDimitry Andric void Abort() { 56568d75effSDimitry Andric internal__exit(3); 56668d75effSDimitry Andric } 56768d75effSDimitry Andric 56868d75effSDimitry Andric #if !SANITIZER_GO 56968d75effSDimitry Andric // Read the file to extract the ImageBase field from the PE header. If ASLR is 57068d75effSDimitry Andric // disabled and this virtual address is available, the loader will typically 57168d75effSDimitry Andric // load the image at this address. Therefore, we call it the preferred base. Any 57268d75effSDimitry Andric // addresses in the DWARF typically assume that the object has been loaded at 57368d75effSDimitry Andric // this address. 574*fe6060f1SDimitry Andric static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) { 57568d75effSDimitry Andric fd_t fd = OpenFile(modname, RdOnly, nullptr); 57668d75effSDimitry Andric if (fd == kInvalidFd) 57768d75effSDimitry Andric return 0; 57868d75effSDimitry Andric FileCloser closer(fd); 57968d75effSDimitry Andric 58068d75effSDimitry Andric // Read just the DOS header. 58168d75effSDimitry Andric IMAGE_DOS_HEADER dos_header; 58268d75effSDimitry Andric uptr bytes_read; 58368d75effSDimitry Andric if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || 58468d75effSDimitry Andric bytes_read != sizeof(dos_header)) 58568d75effSDimitry Andric return 0; 58668d75effSDimitry Andric 58768d75effSDimitry Andric // The file should start with the right signature. 58868d75effSDimitry Andric if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) 58968d75effSDimitry Andric return 0; 59068d75effSDimitry Andric 59168d75effSDimitry Andric // The layout at e_lfanew is: 59268d75effSDimitry Andric // "PE\0\0" 59368d75effSDimitry Andric // IMAGE_FILE_HEADER 59468d75effSDimitry Andric // IMAGE_OPTIONAL_HEADER 59568d75effSDimitry Andric // Seek to e_lfanew and read all that data. 59668d75effSDimitry Andric if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == 59768d75effSDimitry Andric INVALID_SET_FILE_POINTER) 59868d75effSDimitry Andric return 0; 599*fe6060f1SDimitry Andric if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size) 60068d75effSDimitry Andric return 0; 60168d75effSDimitry Andric 60268d75effSDimitry Andric // Check for "PE\0\0" before the PE header. 60368d75effSDimitry Andric char *pe_sig = &buf[0]; 60468d75effSDimitry Andric if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) 60568d75effSDimitry Andric return 0; 60668d75effSDimitry Andric 60768d75effSDimitry Andric // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. 60868d75effSDimitry Andric IMAGE_OPTIONAL_HEADER *pe_header = 60968d75effSDimitry Andric (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); 61068d75effSDimitry Andric 61168d75effSDimitry Andric // Check for more magic in the PE header. 61268d75effSDimitry Andric if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) 61368d75effSDimitry Andric return 0; 61468d75effSDimitry Andric 61568d75effSDimitry Andric // Finally, return the ImageBase. 61668d75effSDimitry Andric return (uptr)pe_header->ImageBase; 61768d75effSDimitry Andric } 61868d75effSDimitry Andric 61968d75effSDimitry Andric void ListOfModules::init() { 62068d75effSDimitry Andric clearOrInit(); 62168d75effSDimitry Andric HANDLE cur_process = GetCurrentProcess(); 62268d75effSDimitry Andric 62368d75effSDimitry Andric // Query the list of modules. Start by assuming there are no more than 256 62468d75effSDimitry Andric // modules and retry if that's not sufficient. 62568d75effSDimitry Andric HMODULE *hmodules = 0; 62668d75effSDimitry Andric uptr modules_buffer_size = sizeof(HMODULE) * 256; 62768d75effSDimitry Andric DWORD bytes_required; 62868d75effSDimitry Andric while (!hmodules) { 62968d75effSDimitry Andric hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); 63068d75effSDimitry Andric CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, 63168d75effSDimitry Andric &bytes_required)); 63268d75effSDimitry Andric if (bytes_required > modules_buffer_size) { 63368d75effSDimitry Andric // Either there turned out to be more than 256 hmodules, or new hmodules 63468d75effSDimitry Andric // could have loaded since the last try. Retry. 63568d75effSDimitry Andric UnmapOrDie(hmodules, modules_buffer_size); 63668d75effSDimitry Andric hmodules = 0; 63768d75effSDimitry Andric modules_buffer_size = bytes_required; 63868d75effSDimitry Andric } 63968d75effSDimitry Andric } 64068d75effSDimitry Andric 641*fe6060f1SDimitry Andric InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) + 642*fe6060f1SDimitry Andric sizeof(IMAGE_OPTIONAL_HEADER)); 643*fe6060f1SDimitry Andric InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength); 644*fe6060f1SDimitry Andric InternalMmapVector<char> module_name(kMaxPathLength); 64568d75effSDimitry Andric // |num_modules| is the number of modules actually present, 64668d75effSDimitry Andric size_t num_modules = bytes_required / sizeof(HMODULE); 64768d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 64868d75effSDimitry Andric HMODULE handle = hmodules[i]; 64968d75effSDimitry Andric MODULEINFO mi; 65068d75effSDimitry Andric if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) 65168d75effSDimitry Andric continue; 65268d75effSDimitry Andric 65368d75effSDimitry Andric // Get the UTF-16 path and convert to UTF-8. 65468d75effSDimitry Andric int modname_utf16_len = 655*fe6060f1SDimitry Andric GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength); 65668d75effSDimitry Andric if (modname_utf16_len == 0) 65768d75effSDimitry Andric modname_utf16[0] = '\0'; 658*fe6060f1SDimitry Andric int module_name_len = ::WideCharToMultiByte( 659*fe6060f1SDimitry Andric CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0], 660*fe6060f1SDimitry Andric kMaxPathLength, NULL, NULL); 66168d75effSDimitry Andric module_name[module_name_len] = '\0'; 66268d75effSDimitry Andric 66368d75effSDimitry Andric uptr base_address = (uptr)mi.lpBaseOfDll; 66468d75effSDimitry Andric uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; 66568d75effSDimitry Andric 66668d75effSDimitry Andric // Adjust the base address of the module so that we get a VA instead of an 66768d75effSDimitry Andric // RVA when computing the module offset. This helps llvm-symbolizer find the 66868d75effSDimitry Andric // right DWARF CU. In the common case that the image is loaded at it's 66968d75effSDimitry Andric // preferred address, we will now print normal virtual addresses. 670*fe6060f1SDimitry Andric uptr preferred_base = 671*fe6060f1SDimitry Andric GetPreferredBase(&module_name[0], &buf[0], buf.size()); 67268d75effSDimitry Andric uptr adjusted_base = base_address - preferred_base; 67368d75effSDimitry Andric 674*fe6060f1SDimitry Andric modules_.push_back(LoadedModule()); 675*fe6060f1SDimitry Andric LoadedModule &cur_module = modules_.back(); 676*fe6060f1SDimitry Andric cur_module.set(&module_name[0], adjusted_base); 67768d75effSDimitry Andric // We add the whole module as one single address range. 67868d75effSDimitry Andric cur_module.addAddressRange(base_address, end_address, /*executable*/ true, 67968d75effSDimitry Andric /*writable*/ true); 68068d75effSDimitry Andric } 68168d75effSDimitry Andric UnmapOrDie(hmodules, modules_buffer_size); 68268d75effSDimitry Andric } 68368d75effSDimitry Andric 68468d75effSDimitry Andric void ListOfModules::fallbackInit() { clear(); } 68568d75effSDimitry Andric 68668d75effSDimitry Andric // We can't use atexit() directly at __asan_init time as the CRT is not fully 68768d75effSDimitry Andric // initialized at this point. Place the functions into a vector and use 68868d75effSDimitry Andric // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). 68968d75effSDimitry Andric InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; 69068d75effSDimitry Andric 69168d75effSDimitry Andric int Atexit(void (*function)(void)) { 69268d75effSDimitry Andric atexit_functions.push_back(function); 69368d75effSDimitry Andric return 0; 69468d75effSDimitry Andric } 69568d75effSDimitry Andric 69668d75effSDimitry Andric static int RunAtexit() { 69768d75effSDimitry Andric TraceLoggingUnregister(g_asan_provider); 69868d75effSDimitry Andric int ret = 0; 69968d75effSDimitry Andric for (uptr i = 0; i < atexit_functions.size(); ++i) { 70068d75effSDimitry Andric ret |= atexit(atexit_functions[i]); 70168d75effSDimitry Andric } 70268d75effSDimitry Andric return ret; 70368d75effSDimitry Andric } 70468d75effSDimitry Andric 70568d75effSDimitry Andric #pragma section(".CRT$XID", long, read) 70668d75effSDimitry Andric __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; 70768d75effSDimitry Andric #endif 70868d75effSDimitry Andric 70968d75effSDimitry Andric // ------------------ sanitizer_libc.h 71068d75effSDimitry Andric fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { 71168d75effSDimitry Andric // FIXME: Use the wide variants to handle Unicode filenames. 71268d75effSDimitry Andric fd_t res; 71368d75effSDimitry Andric if (mode == RdOnly) { 71468d75effSDimitry Andric res = CreateFileA(filename, GENERIC_READ, 71568d75effSDimitry Andric FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 71668d75effSDimitry Andric nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 71768d75effSDimitry Andric } else if (mode == WrOnly) { 71868d75effSDimitry Andric res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 71968d75effSDimitry Andric FILE_ATTRIBUTE_NORMAL, nullptr); 72068d75effSDimitry Andric } else { 72168d75effSDimitry Andric UNIMPLEMENTED(); 72268d75effSDimitry Andric } 72368d75effSDimitry Andric CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); 72468d75effSDimitry Andric CHECK(res != kStderrFd || kStderrFd == kInvalidFd); 72568d75effSDimitry Andric if (res == kInvalidFd && last_error) 72668d75effSDimitry Andric *last_error = GetLastError(); 72768d75effSDimitry Andric return res; 72868d75effSDimitry Andric } 72968d75effSDimitry Andric 73068d75effSDimitry Andric void CloseFile(fd_t fd) { 73168d75effSDimitry Andric CloseHandle(fd); 73268d75effSDimitry Andric } 73368d75effSDimitry Andric 73468d75effSDimitry Andric bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 73568d75effSDimitry Andric error_t *error_p) { 73668d75effSDimitry Andric CHECK(fd != kInvalidFd); 73768d75effSDimitry Andric 73868d75effSDimitry Andric // bytes_read can't be passed directly to ReadFile: 73968d75effSDimitry Andric // uptr is unsigned long long on 64-bit Windows. 74068d75effSDimitry Andric unsigned long num_read_long; 74168d75effSDimitry Andric 74268d75effSDimitry Andric bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); 74368d75effSDimitry Andric if (!success && error_p) 74468d75effSDimitry Andric *error_p = GetLastError(); 74568d75effSDimitry Andric if (bytes_read) 74668d75effSDimitry Andric *bytes_read = num_read_long; 74768d75effSDimitry Andric return success; 74868d75effSDimitry Andric } 74968d75effSDimitry Andric 75068d75effSDimitry Andric bool SupportsColoredOutput(fd_t fd) { 75168d75effSDimitry Andric // FIXME: support colored output. 75268d75effSDimitry Andric return false; 75368d75effSDimitry Andric } 75468d75effSDimitry Andric 75568d75effSDimitry Andric bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 75668d75effSDimitry Andric error_t *error_p) { 75768d75effSDimitry Andric CHECK(fd != kInvalidFd); 75868d75effSDimitry Andric 75968d75effSDimitry Andric // Handle null optional parameters. 76068d75effSDimitry Andric error_t dummy_error; 76168d75effSDimitry Andric error_p = error_p ? error_p : &dummy_error; 76268d75effSDimitry Andric uptr dummy_bytes_written; 76368d75effSDimitry Andric bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; 76468d75effSDimitry Andric 76568d75effSDimitry Andric // Initialize output parameters in case we fail. 76668d75effSDimitry Andric *error_p = 0; 76768d75effSDimitry Andric *bytes_written = 0; 76868d75effSDimitry Andric 76968d75effSDimitry Andric // Map the conventional Unix fds 1 and 2 to Windows handles. They might be 77068d75effSDimitry Andric // closed, in which case this will fail. 77168d75effSDimitry Andric if (fd == kStdoutFd || fd == kStderrFd) { 77268d75effSDimitry Andric fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); 77368d75effSDimitry Andric if (fd == 0) { 77468d75effSDimitry Andric *error_p = ERROR_INVALID_HANDLE; 77568d75effSDimitry Andric return false; 77668d75effSDimitry Andric } 77768d75effSDimitry Andric } 77868d75effSDimitry Andric 77968d75effSDimitry Andric DWORD bytes_written_32; 78068d75effSDimitry Andric if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { 78168d75effSDimitry Andric *error_p = GetLastError(); 78268d75effSDimitry Andric return false; 78368d75effSDimitry Andric } else { 78468d75effSDimitry Andric *bytes_written = bytes_written_32; 78568d75effSDimitry Andric return true; 78668d75effSDimitry Andric } 78768d75effSDimitry Andric } 78868d75effSDimitry Andric 78968d75effSDimitry Andric uptr internal_sched_yield() { 79068d75effSDimitry Andric Sleep(0); 79168d75effSDimitry Andric return 0; 79268d75effSDimitry Andric } 79368d75effSDimitry Andric 79468d75effSDimitry Andric void internal__exit(int exitcode) { 79568d75effSDimitry Andric TraceLoggingUnregister(g_asan_provider); 79668d75effSDimitry Andric // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. 79768d75effSDimitry Andric // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, 79868d75effSDimitry Andric // so add our own breakpoint here. 79968d75effSDimitry Andric if (::IsDebuggerPresent()) 80068d75effSDimitry Andric __debugbreak(); 80168d75effSDimitry Andric TerminateProcess(GetCurrentProcess(), exitcode); 80268d75effSDimitry Andric BUILTIN_UNREACHABLE(); 80368d75effSDimitry Andric } 80468d75effSDimitry Andric 80568d75effSDimitry Andric uptr internal_ftruncate(fd_t fd, uptr size) { 80668d75effSDimitry Andric UNIMPLEMENTED(); 80768d75effSDimitry Andric } 80868d75effSDimitry Andric 80968d75effSDimitry Andric uptr GetRSS() { 81068d75effSDimitry Andric PROCESS_MEMORY_COUNTERS counters; 81168d75effSDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) 81268d75effSDimitry Andric return 0; 81368d75effSDimitry Andric return counters.WorkingSetSize; 81468d75effSDimitry Andric } 81568d75effSDimitry Andric 8165ffd83dbSDimitry Andric void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } 81768d75effSDimitry Andric void internal_join_thread(void *th) { } 81868d75effSDimitry Andric 819*fe6060f1SDimitry Andric void FutexWait(atomic_uint32_t *p, u32 cmp) { 820*fe6060f1SDimitry Andric WaitOnAddress(p, &cmp, sizeof(cmp), INFINITE); 821*fe6060f1SDimitry Andric } 822*fe6060f1SDimitry Andric 823*fe6060f1SDimitry Andric void FutexWake(atomic_uint32_t *p, u32 count) { 824*fe6060f1SDimitry Andric if (count == 1) 825*fe6060f1SDimitry Andric WakeByAddressSingle(p); 826*fe6060f1SDimitry Andric else 827*fe6060f1SDimitry Andric WakeByAddressAll(p); 828*fe6060f1SDimitry Andric } 829*fe6060f1SDimitry Andric 83068d75effSDimitry Andric // ---------------------- BlockingMutex ---------------- {{{1 83168d75effSDimitry Andric 83268d75effSDimitry Andric BlockingMutex::BlockingMutex() { 83368d75effSDimitry Andric CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_)); 83468d75effSDimitry Andric internal_memset(this, 0, sizeof(*this)); 83568d75effSDimitry Andric } 83668d75effSDimitry Andric 83768d75effSDimitry Andric void BlockingMutex::Lock() { 83868d75effSDimitry Andric AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_); 83968d75effSDimitry Andric CHECK_EQ(owner_, 0); 84068d75effSDimitry Andric owner_ = GetThreadSelf(); 84168d75effSDimitry Andric } 84268d75effSDimitry Andric 84368d75effSDimitry Andric void BlockingMutex::Unlock() { 84468d75effSDimitry Andric CheckLocked(); 84568d75effSDimitry Andric owner_ = 0; 84668d75effSDimitry Andric ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_); 84768d75effSDimitry Andric } 84868d75effSDimitry Andric 849*fe6060f1SDimitry Andric void BlockingMutex::CheckLocked() const { CHECK_EQ(owner_, GetThreadSelf()); } 85068d75effSDimitry Andric 85168d75effSDimitry Andric uptr GetTlsSize() { 85268d75effSDimitry Andric return 0; 85368d75effSDimitry Andric } 85468d75effSDimitry Andric 85568d75effSDimitry Andric void InitTlsSize() { 85668d75effSDimitry Andric } 85768d75effSDimitry Andric 85868d75effSDimitry Andric void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 85968d75effSDimitry Andric uptr *tls_addr, uptr *tls_size) { 86068d75effSDimitry Andric #if SANITIZER_GO 86168d75effSDimitry Andric *stk_addr = 0; 86268d75effSDimitry Andric *stk_size = 0; 86368d75effSDimitry Andric *tls_addr = 0; 86468d75effSDimitry Andric *tls_size = 0; 86568d75effSDimitry Andric #else 86668d75effSDimitry Andric uptr stack_top, stack_bottom; 86768d75effSDimitry Andric GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 86868d75effSDimitry Andric *stk_addr = stack_bottom; 86968d75effSDimitry Andric *stk_size = stack_top - stack_bottom; 87068d75effSDimitry Andric *tls_addr = 0; 87168d75effSDimitry Andric *tls_size = 0; 87268d75effSDimitry Andric #endif 87368d75effSDimitry Andric } 87468d75effSDimitry Andric 87568d75effSDimitry Andric void ReportFile::Write(const char *buffer, uptr length) { 87668d75effSDimitry Andric SpinMutexLock l(mu); 87768d75effSDimitry Andric ReopenIfNecessary(); 87868d75effSDimitry Andric if (!WriteToFile(fd, buffer, length)) { 87968d75effSDimitry Andric // stderr may be closed, but we may be able to print to the debugger 88068d75effSDimitry Andric // instead. This is the case when launching a program from Visual Studio, 88168d75effSDimitry Andric // and the following routine should write to its console. 88268d75effSDimitry Andric OutputDebugStringA(buffer); 88368d75effSDimitry Andric } 88468d75effSDimitry Andric } 88568d75effSDimitry Andric 88668d75effSDimitry Andric void SetAlternateSignalStack() { 88768d75effSDimitry Andric // FIXME: Decide what to do on Windows. 88868d75effSDimitry Andric } 88968d75effSDimitry Andric 89068d75effSDimitry Andric void UnsetAlternateSignalStack() { 89168d75effSDimitry Andric // FIXME: Decide what to do on Windows. 89268d75effSDimitry Andric } 89368d75effSDimitry Andric 89468d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) { 89568d75effSDimitry Andric (void)handler; 89668d75effSDimitry Andric // FIXME: Decide what to do on Windows. 89768d75effSDimitry Andric } 89868d75effSDimitry Andric 89968d75effSDimitry Andric HandleSignalMode GetHandleSignalMode(int signum) { 90068d75effSDimitry Andric // FIXME: Decide what to do on Windows. 90168d75effSDimitry Andric return kHandleSignalNo; 90268d75effSDimitry Andric } 90368d75effSDimitry Andric 90468d75effSDimitry Andric // Check based on flags if we should handle this exception. 90568d75effSDimitry Andric bool IsHandledDeadlyException(DWORD exceptionCode) { 90668d75effSDimitry Andric switch (exceptionCode) { 90768d75effSDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 90868d75effSDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 90968d75effSDimitry Andric case EXCEPTION_STACK_OVERFLOW: 91068d75effSDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 91168d75effSDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 91268d75effSDimitry Andric return common_flags()->handle_segv; 91368d75effSDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 91468d75effSDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 91568d75effSDimitry Andric case EXCEPTION_BREAKPOINT: 91668d75effSDimitry Andric return common_flags()->handle_sigill; 91768d75effSDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 91868d75effSDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 91968d75effSDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 92068d75effSDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 92168d75effSDimitry Andric case EXCEPTION_FLT_OVERFLOW: 92268d75effSDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 92368d75effSDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 92468d75effSDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 92568d75effSDimitry Andric case EXCEPTION_INT_OVERFLOW: 92668d75effSDimitry Andric return common_flags()->handle_sigfpe; 92768d75effSDimitry Andric } 92868d75effSDimitry Andric return false; 92968d75effSDimitry Andric } 93068d75effSDimitry Andric 93168d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) { 93268d75effSDimitry Andric SYSTEM_INFO si; 93368d75effSDimitry Andric GetNativeSystemInfo(&si); 93468d75effSDimitry Andric uptr page_size = si.dwPageSize; 93568d75effSDimitry Andric uptr page_mask = ~(page_size - 1); 93668d75effSDimitry Andric 93768d75effSDimitry Andric for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; 93868d75effSDimitry Andric page <= end;) { 93968d75effSDimitry Andric MEMORY_BASIC_INFORMATION info; 94068d75effSDimitry Andric if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) 94168d75effSDimitry Andric return false; 94268d75effSDimitry Andric 94368d75effSDimitry Andric if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || 94468d75effSDimitry Andric info.Protect == PAGE_EXECUTE) 94568d75effSDimitry Andric return false; 94668d75effSDimitry Andric 94768d75effSDimitry Andric if (info.RegionSize == 0) 94868d75effSDimitry Andric return false; 94968d75effSDimitry Andric 95068d75effSDimitry Andric page += info.RegionSize; 95168d75effSDimitry Andric } 95268d75effSDimitry Andric 95368d75effSDimitry Andric return true; 95468d75effSDimitry Andric } 95568d75effSDimitry Andric 95668d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { 95768d75effSDimitry Andric return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; 95868d75effSDimitry Andric } 95968d75effSDimitry Andric 96068d75effSDimitry Andric void SignalContext::InitPcSpBp() { 96168d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 96268d75effSDimitry Andric CONTEXT *context_record = (CONTEXT *)context; 96368d75effSDimitry Andric 96468d75effSDimitry Andric pc = (uptr)exception_record->ExceptionAddress; 96568d75effSDimitry Andric #ifdef _WIN64 96668d75effSDimitry Andric bp = (uptr)context_record->Rbp; 96768d75effSDimitry Andric sp = (uptr)context_record->Rsp; 96868d75effSDimitry Andric #else 96968d75effSDimitry Andric bp = (uptr)context_record->Ebp; 97068d75effSDimitry Andric sp = (uptr)context_record->Esp; 97168d75effSDimitry Andric #endif 97268d75effSDimitry Andric } 97368d75effSDimitry Andric 97468d75effSDimitry Andric uptr SignalContext::GetAddress() const { 97568d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 976e8d8bef9SDimitry Andric if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) 97768d75effSDimitry Andric return exception_record->ExceptionInformation[1]; 978e8d8bef9SDimitry Andric return (uptr)exception_record->ExceptionAddress; 97968d75effSDimitry Andric } 98068d75effSDimitry Andric 98168d75effSDimitry Andric bool SignalContext::IsMemoryAccess() const { 982e8d8bef9SDimitry Andric return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode == 983e8d8bef9SDimitry Andric EXCEPTION_ACCESS_VIOLATION; 98468d75effSDimitry Andric } 98568d75effSDimitry Andric 986e8d8bef9SDimitry Andric bool SignalContext::IsTrueFaultingAddress() const { return true; } 98768d75effSDimitry Andric 98868d75effSDimitry Andric SignalContext::WriteFlag SignalContext::GetWriteFlag() const { 98968d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 990e8d8bef9SDimitry Andric 991e8d8bef9SDimitry Andric // The write flag is only available for access violation exceptions. 992e8d8bef9SDimitry Andric if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) 993e8d8bef9SDimitry Andric return SignalContext::UNKNOWN; 994e8d8bef9SDimitry Andric 99568d75effSDimitry Andric // The contents of this array are documented at 996e8d8bef9SDimitry Andric // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record 99768d75effSDimitry Andric // The first element indicates read as 0, write as 1, or execute as 8. The 99868d75effSDimitry Andric // second element is the faulting address. 99968d75effSDimitry Andric switch (exception_record->ExceptionInformation[0]) { 100068d75effSDimitry Andric case 0: 100168d75effSDimitry Andric return SignalContext::READ; 100268d75effSDimitry Andric case 1: 100368d75effSDimitry Andric return SignalContext::WRITE; 100468d75effSDimitry Andric case 8: 100568d75effSDimitry Andric return SignalContext::UNKNOWN; 100668d75effSDimitry Andric } 100768d75effSDimitry Andric return SignalContext::UNKNOWN; 100868d75effSDimitry Andric } 100968d75effSDimitry Andric 101068d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { 101168d75effSDimitry Andric // FIXME: Implement this. 101268d75effSDimitry Andric } 101368d75effSDimitry Andric 101468d75effSDimitry Andric int SignalContext::GetType() const { 101568d75effSDimitry Andric return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode; 101668d75effSDimitry Andric } 101768d75effSDimitry Andric 101868d75effSDimitry Andric const char *SignalContext::Describe() const { 101968d75effSDimitry Andric unsigned code = GetType(); 102068d75effSDimitry Andric // Get the string description of the exception if this is a known deadly 102168d75effSDimitry Andric // exception. 102268d75effSDimitry Andric switch (code) { 102368d75effSDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 102468d75effSDimitry Andric return "access-violation"; 102568d75effSDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 102668d75effSDimitry Andric return "array-bounds-exceeded"; 102768d75effSDimitry Andric case EXCEPTION_STACK_OVERFLOW: 102868d75effSDimitry Andric return "stack-overflow"; 102968d75effSDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 103068d75effSDimitry Andric return "datatype-misalignment"; 103168d75effSDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 103268d75effSDimitry Andric return "in-page-error"; 103368d75effSDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 103468d75effSDimitry Andric return "illegal-instruction"; 103568d75effSDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 103668d75effSDimitry Andric return "priv-instruction"; 103768d75effSDimitry Andric case EXCEPTION_BREAKPOINT: 103868d75effSDimitry Andric return "breakpoint"; 103968d75effSDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 104068d75effSDimitry Andric return "flt-denormal-operand"; 104168d75effSDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 104268d75effSDimitry Andric return "flt-divide-by-zero"; 104368d75effSDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 104468d75effSDimitry Andric return "flt-inexact-result"; 104568d75effSDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 104668d75effSDimitry Andric return "flt-invalid-operation"; 104768d75effSDimitry Andric case EXCEPTION_FLT_OVERFLOW: 104868d75effSDimitry Andric return "flt-overflow"; 104968d75effSDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 105068d75effSDimitry Andric return "flt-stack-check"; 105168d75effSDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 105268d75effSDimitry Andric return "flt-underflow"; 105368d75effSDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 105468d75effSDimitry Andric return "int-divide-by-zero"; 105568d75effSDimitry Andric case EXCEPTION_INT_OVERFLOW: 105668d75effSDimitry Andric return "int-overflow"; 105768d75effSDimitry Andric } 105868d75effSDimitry Andric return "unknown exception"; 105968d75effSDimitry Andric } 106068d75effSDimitry Andric 106168d75effSDimitry Andric uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 1062*fe6060f1SDimitry Andric if (buf_len == 0) 106368d75effSDimitry Andric return 0; 1064*fe6060f1SDimitry Andric 1065*fe6060f1SDimitry Andric // Get the UTF-16 path and convert to UTF-8. 1066*fe6060f1SDimitry Andric InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength); 1067*fe6060f1SDimitry Andric int binname_utf16_len = 1068*fe6060f1SDimitry Andric GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength); 1069*fe6060f1SDimitry Andric if (binname_utf16_len == 0) { 1070*fe6060f1SDimitry Andric buf[0] = '\0'; 1071*fe6060f1SDimitry Andric return 0; 1072*fe6060f1SDimitry Andric } 1073*fe6060f1SDimitry Andric int binary_name_len = 1074*fe6060f1SDimitry Andric ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len, 1075*fe6060f1SDimitry Andric buf, buf_len, NULL, NULL); 1076*fe6060f1SDimitry Andric if ((unsigned)binary_name_len == buf_len) 1077*fe6060f1SDimitry Andric --binary_name_len; 1078*fe6060f1SDimitry Andric buf[binary_name_len] = '\0'; 1079*fe6060f1SDimitry Andric return binary_name_len; 108068d75effSDimitry Andric } 108168d75effSDimitry Andric 108268d75effSDimitry Andric uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { 108368d75effSDimitry Andric return ReadBinaryName(buf, buf_len); 108468d75effSDimitry Andric } 108568d75effSDimitry Andric 108668d75effSDimitry Andric void CheckVMASize() { 108768d75effSDimitry Andric // Do nothing. 108868d75effSDimitry Andric } 108968d75effSDimitry Andric 109068d75effSDimitry Andric void InitializePlatformEarly() { 109168d75effSDimitry Andric // Do nothing. 109268d75effSDimitry Andric } 109368d75effSDimitry Andric 109468d75effSDimitry Andric void MaybeReexec() { 109568d75effSDimitry Andric // No need to re-exec on Windows. 109668d75effSDimitry Andric } 109768d75effSDimitry Andric 109868d75effSDimitry Andric void CheckASLR() { 109968d75effSDimitry Andric // Do nothing 110068d75effSDimitry Andric } 110168d75effSDimitry Andric 110268d75effSDimitry Andric void CheckMPROTECT() { 110368d75effSDimitry Andric // Do nothing 110468d75effSDimitry Andric } 110568d75effSDimitry Andric 110668d75effSDimitry Andric char **GetArgv() { 110768d75effSDimitry Andric // FIXME: Actually implement this function. 110868d75effSDimitry Andric return 0; 110968d75effSDimitry Andric } 111068d75effSDimitry Andric 111168d75effSDimitry Andric char **GetEnviron() { 111268d75effSDimitry Andric // FIXME: Actually implement this function. 111368d75effSDimitry Andric return 0; 111468d75effSDimitry Andric } 111568d75effSDimitry Andric 111668d75effSDimitry Andric pid_t StartSubprocess(const char *program, const char *const argv[], 11175ffd83dbSDimitry Andric const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, 11185ffd83dbSDimitry Andric fd_t stderr_fd) { 111968d75effSDimitry Andric // FIXME: implement on this platform 112068d75effSDimitry Andric // Should be implemented based on 112168d75effSDimitry Andric // SymbolizerProcess::StarAtSymbolizerSubprocess 112268d75effSDimitry Andric // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. 112368d75effSDimitry Andric return -1; 112468d75effSDimitry Andric } 112568d75effSDimitry Andric 112668d75effSDimitry Andric bool IsProcessRunning(pid_t pid) { 112768d75effSDimitry Andric // FIXME: implement on this platform. 112868d75effSDimitry Andric return false; 112968d75effSDimitry Andric } 113068d75effSDimitry Andric 113168d75effSDimitry Andric int WaitForProcess(pid_t pid) { return -1; } 113268d75effSDimitry Andric 113368d75effSDimitry Andric // FIXME implement on this platform. 113468d75effSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } 113568d75effSDimitry Andric 113668d75effSDimitry Andric void CheckNoDeepBind(const char *filename, int flag) { 113768d75effSDimitry Andric // Do nothing. 113868d75effSDimitry Andric } 113968d75effSDimitry Andric 114068d75effSDimitry Andric // FIXME: implement on this platform. 114168d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) { 114268d75effSDimitry Andric UNIMPLEMENTED(); 114368d75effSDimitry Andric } 114468d75effSDimitry Andric 114568d75effSDimitry Andric u32 GetNumberOfCPUs() { 114668d75effSDimitry Andric SYSTEM_INFO sysinfo = {}; 114768d75effSDimitry Andric GetNativeSystemInfo(&sysinfo); 114868d75effSDimitry Andric return sysinfo.dwNumberOfProcessors; 114968d75effSDimitry Andric } 115068d75effSDimitry Andric 115168d75effSDimitry Andric #if SANITIZER_WIN_TRACE 115268d75effSDimitry Andric // TODO(mcgov): Rename this project-wide to PlatformLogInit 115368d75effSDimitry Andric void AndroidLogInit(void) { 115468d75effSDimitry Andric HRESULT hr = TraceLoggingRegister(g_asan_provider); 115568d75effSDimitry Andric if (!SUCCEEDED(hr)) 115668d75effSDimitry Andric return; 115768d75effSDimitry Andric } 115868d75effSDimitry Andric 115968d75effSDimitry Andric void SetAbortMessage(const char *) {} 116068d75effSDimitry Andric 116168d75effSDimitry Andric void LogFullErrorReport(const char *buffer) { 116268d75effSDimitry Andric if (common_flags()->log_to_syslog) { 116368d75effSDimitry Andric InternalMmapVector<wchar_t> filename; 116468d75effSDimitry Andric DWORD filename_length = 0; 116568d75effSDimitry Andric do { 116668d75effSDimitry Andric filename.resize(filename.size() + 0x100); 116768d75effSDimitry Andric filename_length = 116868d75effSDimitry Andric GetModuleFileNameW(NULL, filename.begin(), filename.size()); 116968d75effSDimitry Andric } while (filename_length >= filename.size()); 117068d75effSDimitry Andric TraceLoggingWrite(g_asan_provider, "AsanReportEvent", 117168d75effSDimitry Andric TraceLoggingValue(filename.begin(), "ExecutableName"), 117268d75effSDimitry Andric TraceLoggingValue(buffer, "AsanReportContents")); 117368d75effSDimitry Andric } 117468d75effSDimitry Andric } 117568d75effSDimitry Andric #endif // SANITIZER_WIN_TRACE 117668d75effSDimitry Andric 1177e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {} 1178e8d8bef9SDimitry Andric 117968d75effSDimitry Andric } // namespace __sanitizer 118068d75effSDimitry Andric 118168d75effSDimitry Andric #endif // _WIN32 1182