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 47fe6060f1SDimitry Andric // For WaitOnAddress 48fe6060f1SDimitry Andric # pragma comment(lib, "synchronization.lib") 49fe6060f1SDimitry 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 3394824e7fdSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) { 3404824e7fdSDimitry Andric DWORD old_protection; 3414824e7fdSDimitry Andric return VirtualProtect((LPVOID)addr, size, PAGE_READONLY, &old_protection); 3424824e7fdSDimitry Andric } 3434824e7fdSDimitry Andric 34468d75effSDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) { 345fe6060f1SDimitry Andric uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()), 346fe6060f1SDimitry Andric end_aligned = RoundDownTo(end, GetPageSizeCached()); 347fe6060f1SDimitry Andric CHECK(beg < end); // make sure the region is sane 348fe6060f1SDimitry Andric if (beg_aligned == end_aligned) // make sure we're freeing at least 1 page; 349fe6060f1SDimitry Andric return; 350fe6060f1SDimitry Andric UnmapOrDie((void *)beg, end_aligned - beg_aligned); 35168d75effSDimitry Andric } 35268d75effSDimitry Andric 35368d75effSDimitry Andric void SetShadowRegionHugePageMode(uptr addr, uptr size) { 35468d75effSDimitry Andric // FIXME: probably similar to ReleaseMemoryToOS. 35568d75effSDimitry Andric } 35668d75effSDimitry Andric 35768d75effSDimitry Andric bool DontDumpShadowMemory(uptr addr, uptr length) { 35868d75effSDimitry Andric // This is almost useless on 32-bits. 35968d75effSDimitry Andric // FIXME: add madvise-analog when we move to 64-bits. 36068d75effSDimitry Andric return true; 36168d75effSDimitry Andric } 36268d75effSDimitry Andric 363e8d8bef9SDimitry Andric uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale, 364e8d8bef9SDimitry Andric uptr min_shadow_base_alignment, 365e8d8bef9SDimitry Andric UNUSED uptr &high_mem_end) { 366e8d8bef9SDimitry Andric const uptr granularity = GetMmapGranularity(); 367e8d8bef9SDimitry Andric const uptr alignment = 368e8d8bef9SDimitry Andric Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment); 369e8d8bef9SDimitry Andric const uptr left_padding = 370e8d8bef9SDimitry Andric Max<uptr>(granularity, 1ULL << min_shadow_base_alignment); 371e8d8bef9SDimitry Andric uptr space_size = shadow_size_bytes + left_padding; 372e8d8bef9SDimitry Andric uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, 373e8d8bef9SDimitry Andric granularity, nullptr, nullptr); 374e8d8bef9SDimitry Andric CHECK_NE((uptr)0, shadow_start); 375e8d8bef9SDimitry Andric CHECK(IsAligned(shadow_start, alignment)); 376e8d8bef9SDimitry Andric return shadow_start; 377e8d8bef9SDimitry Andric } 378e8d8bef9SDimitry Andric 37968d75effSDimitry Andric uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, 38068d75effSDimitry Andric uptr *largest_gap_found, 38168d75effSDimitry Andric uptr *max_occupied_addr) { 38268d75effSDimitry Andric uptr address = 0; 38368d75effSDimitry Andric while (true) { 38468d75effSDimitry Andric MEMORY_BASIC_INFORMATION info; 38568d75effSDimitry Andric if (!::VirtualQuery((void*)address, &info, sizeof(info))) 38668d75effSDimitry Andric return 0; 38768d75effSDimitry Andric 38868d75effSDimitry Andric if (info.State == MEM_FREE) { 38968d75effSDimitry Andric uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding, 39068d75effSDimitry Andric alignment); 39168d75effSDimitry Andric if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize) 39268d75effSDimitry Andric return shadow_address; 39368d75effSDimitry Andric } 39468d75effSDimitry Andric 39568d75effSDimitry Andric // Move to the next region. 39668d75effSDimitry Andric address = (uptr)info.BaseAddress + info.RegionSize; 39768d75effSDimitry Andric } 39868d75effSDimitry Andric return 0; 39968d75effSDimitry Andric } 40068d75effSDimitry Andric 401fe6060f1SDimitry Andric uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size, 402fe6060f1SDimitry Andric uptr num_aliases, uptr ring_buffer_size) { 403fe6060f1SDimitry Andric CHECK(false && "HWASan aliasing is unimplemented on Windows"); 404fe6060f1SDimitry Andric return 0; 405fe6060f1SDimitry Andric } 406fe6060f1SDimitry Andric 40768d75effSDimitry Andric bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 40868d75effSDimitry Andric MEMORY_BASIC_INFORMATION mbi; 40968d75effSDimitry Andric CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); 41068d75effSDimitry Andric return mbi.Protect == PAGE_NOACCESS && 41168d75effSDimitry Andric (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; 41268d75effSDimitry Andric } 41368d75effSDimitry Andric 41468d75effSDimitry Andric void *MapFileToMemory(const char *file_name, uptr *buff_size) { 41568d75effSDimitry Andric UNIMPLEMENTED(); 41668d75effSDimitry Andric } 41768d75effSDimitry Andric 41868d75effSDimitry Andric void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 41968d75effSDimitry Andric UNIMPLEMENTED(); 42068d75effSDimitry Andric } 42168d75effSDimitry Andric 42268d75effSDimitry Andric static const int kMaxEnvNameLength = 128; 42368d75effSDimitry Andric static const DWORD kMaxEnvValueLength = 32767; 42468d75effSDimitry Andric 42568d75effSDimitry Andric namespace { 42668d75effSDimitry Andric 42768d75effSDimitry Andric struct EnvVariable { 42868d75effSDimitry Andric char name[kMaxEnvNameLength]; 42968d75effSDimitry Andric char value[kMaxEnvValueLength]; 43068d75effSDimitry Andric }; 43168d75effSDimitry Andric 43268d75effSDimitry Andric } // namespace 43368d75effSDimitry Andric 43468d75effSDimitry Andric static const int kEnvVariables = 5; 43568d75effSDimitry Andric static EnvVariable env_vars[kEnvVariables]; 43668d75effSDimitry Andric static int num_env_vars; 43768d75effSDimitry Andric 43868d75effSDimitry Andric const char *GetEnv(const char *name) { 43968d75effSDimitry Andric // Note: this implementation caches the values of the environment variables 44068d75effSDimitry Andric // and limits their quantity. 44168d75effSDimitry Andric for (int i = 0; i < num_env_vars; i++) { 44268d75effSDimitry Andric if (0 == internal_strcmp(name, env_vars[i].name)) 44368d75effSDimitry Andric return env_vars[i].value; 44468d75effSDimitry Andric } 44568d75effSDimitry Andric CHECK_LT(num_env_vars, kEnvVariables); 44668d75effSDimitry Andric DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 44768d75effSDimitry Andric kMaxEnvValueLength); 44868d75effSDimitry Andric if (rv > 0 && rv < kMaxEnvValueLength) { 44968d75effSDimitry Andric CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 45068d75effSDimitry Andric internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 45168d75effSDimitry Andric num_env_vars++; 45268d75effSDimitry Andric return env_vars[num_env_vars - 1].value; 45368d75effSDimitry Andric } 45468d75effSDimitry Andric return 0; 45568d75effSDimitry Andric } 45668d75effSDimitry Andric 45768d75effSDimitry Andric const char *GetPwd() { 45868d75effSDimitry Andric UNIMPLEMENTED(); 45968d75effSDimitry Andric } 46068d75effSDimitry Andric 46168d75effSDimitry Andric u32 GetUid() { 46268d75effSDimitry Andric UNIMPLEMENTED(); 46368d75effSDimitry Andric } 46468d75effSDimitry Andric 46568d75effSDimitry Andric namespace { 46668d75effSDimitry Andric struct ModuleInfo { 46768d75effSDimitry Andric const char *filepath; 46868d75effSDimitry Andric uptr base_address; 46968d75effSDimitry Andric uptr end_address; 47068d75effSDimitry Andric }; 47168d75effSDimitry Andric 47268d75effSDimitry Andric #if !SANITIZER_GO 47368d75effSDimitry Andric int CompareModulesBase(const void *pl, const void *pr) { 47468d75effSDimitry Andric const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr; 47568d75effSDimitry Andric if (l->base_address < r->base_address) 47668d75effSDimitry Andric return -1; 47768d75effSDimitry Andric return l->base_address > r->base_address; 47868d75effSDimitry Andric } 47968d75effSDimitry Andric #endif 48068d75effSDimitry Andric } // namespace 48168d75effSDimitry Andric 48268d75effSDimitry Andric #if !SANITIZER_GO 48368d75effSDimitry Andric void DumpProcessMap() { 48468d75effSDimitry Andric Report("Dumping process modules:\n"); 48568d75effSDimitry Andric ListOfModules modules; 48668d75effSDimitry Andric modules.init(); 48768d75effSDimitry Andric uptr num_modules = modules.size(); 48868d75effSDimitry Andric 48968d75effSDimitry Andric InternalMmapVector<ModuleInfo> module_infos(num_modules); 49068d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 49168d75effSDimitry Andric module_infos[i].filepath = modules[i].full_name(); 49268d75effSDimitry Andric module_infos[i].base_address = modules[i].ranges().front()->beg; 49368d75effSDimitry Andric module_infos[i].end_address = modules[i].ranges().back()->end; 49468d75effSDimitry Andric } 49568d75effSDimitry Andric qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), 49668d75effSDimitry Andric CompareModulesBase); 49768d75effSDimitry Andric 49868d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 49968d75effSDimitry Andric const ModuleInfo &mi = module_infos[i]; 50068d75effSDimitry Andric if (mi.end_address != 0) { 50168d75effSDimitry Andric Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, 50268d75effSDimitry Andric mi.filepath[0] ? mi.filepath : "[no name]"); 50368d75effSDimitry Andric } else if (mi.filepath[0]) { 50468d75effSDimitry Andric Printf("\t??\?-??? %s\n", mi.filepath); 50568d75effSDimitry Andric } else { 50668d75effSDimitry Andric Printf("\t???\n"); 50768d75effSDimitry Andric } 50868d75effSDimitry Andric } 50968d75effSDimitry Andric } 51068d75effSDimitry Andric #endif 51168d75effSDimitry Andric 51268d75effSDimitry Andric void DisableCoreDumperIfNecessary() { 51368d75effSDimitry Andric // Do nothing. 51468d75effSDimitry Andric } 51568d75effSDimitry Andric 51668d75effSDimitry Andric void ReExec() { 51768d75effSDimitry Andric UNIMPLEMENTED(); 51868d75effSDimitry Andric } 51968d75effSDimitry Andric 52068d75effSDimitry Andric void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} 52168d75effSDimitry Andric 52268d75effSDimitry Andric bool StackSizeIsUnlimited() { 52368d75effSDimitry Andric UNIMPLEMENTED(); 52468d75effSDimitry Andric } 52568d75effSDimitry Andric 52668d75effSDimitry Andric void SetStackSizeLimitInBytes(uptr limit) { 52768d75effSDimitry Andric UNIMPLEMENTED(); 52868d75effSDimitry Andric } 52968d75effSDimitry Andric 53068d75effSDimitry Andric bool AddressSpaceIsUnlimited() { 53168d75effSDimitry Andric UNIMPLEMENTED(); 53268d75effSDimitry Andric } 53368d75effSDimitry Andric 53468d75effSDimitry Andric void SetAddressSpaceUnlimited() { 53568d75effSDimitry Andric UNIMPLEMENTED(); 53668d75effSDimitry Andric } 53768d75effSDimitry Andric 53868d75effSDimitry Andric bool IsPathSeparator(const char c) { 53968d75effSDimitry Andric return c == '\\' || c == '/'; 54068d75effSDimitry Andric } 54168d75effSDimitry Andric 54268d75effSDimitry Andric static bool IsAlpha(char c) { 54368d75effSDimitry Andric c = ToLower(c); 54468d75effSDimitry Andric return c >= 'a' && c <= 'z'; 54568d75effSDimitry Andric } 54668d75effSDimitry Andric 54768d75effSDimitry Andric bool IsAbsolutePath(const char *path) { 54868d75effSDimitry Andric return path != nullptr && IsAlpha(path[0]) && path[1] == ':' && 54968d75effSDimitry Andric IsPathSeparator(path[2]); 55068d75effSDimitry Andric } 55168d75effSDimitry Andric 552fe6060f1SDimitry Andric void internal_usleep(u64 useconds) { Sleep(useconds / 1000); } 55368d75effSDimitry Andric 55468d75effSDimitry Andric u64 NanoTime() { 55568d75effSDimitry Andric static LARGE_INTEGER frequency = {}; 55668d75effSDimitry Andric LARGE_INTEGER counter; 55768d75effSDimitry Andric if (UNLIKELY(frequency.QuadPart == 0)) { 55868d75effSDimitry Andric QueryPerformanceFrequency(&frequency); 55968d75effSDimitry Andric CHECK_NE(frequency.QuadPart, 0); 56068d75effSDimitry Andric } 56168d75effSDimitry Andric QueryPerformanceCounter(&counter); 56268d75effSDimitry Andric counter.QuadPart *= 1000ULL * 1000000ULL; 56368d75effSDimitry Andric counter.QuadPart /= frequency.QuadPart; 56468d75effSDimitry Andric return counter.QuadPart; 56568d75effSDimitry Andric } 56668d75effSDimitry Andric 56768d75effSDimitry Andric u64 MonotonicNanoTime() { return NanoTime(); } 56868d75effSDimitry Andric 56968d75effSDimitry Andric void Abort() { 57068d75effSDimitry Andric internal__exit(3); 57168d75effSDimitry Andric } 57268d75effSDimitry Andric 5730eae32dcSDimitry Andric bool CreateDir(const char *pathname) { 5740eae32dcSDimitry Andric return CreateDirectoryA(pathname, nullptr) != 0; 5750eae32dcSDimitry Andric } 576349cc55cSDimitry Andric 57768d75effSDimitry Andric #if !SANITIZER_GO 57868d75effSDimitry Andric // Read the file to extract the ImageBase field from the PE header. If ASLR is 57968d75effSDimitry Andric // disabled and this virtual address is available, the loader will typically 58068d75effSDimitry Andric // load the image at this address. Therefore, we call it the preferred base. Any 58168d75effSDimitry Andric // addresses in the DWARF typically assume that the object has been loaded at 58268d75effSDimitry Andric // this address. 583fe6060f1SDimitry Andric static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) { 58468d75effSDimitry Andric fd_t fd = OpenFile(modname, RdOnly, nullptr); 58568d75effSDimitry Andric if (fd == kInvalidFd) 58668d75effSDimitry Andric return 0; 58768d75effSDimitry Andric FileCloser closer(fd); 58868d75effSDimitry Andric 58968d75effSDimitry Andric // Read just the DOS header. 59068d75effSDimitry Andric IMAGE_DOS_HEADER dos_header; 59168d75effSDimitry Andric uptr bytes_read; 59268d75effSDimitry Andric if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || 59368d75effSDimitry Andric bytes_read != sizeof(dos_header)) 59468d75effSDimitry Andric return 0; 59568d75effSDimitry Andric 59668d75effSDimitry Andric // The file should start with the right signature. 59768d75effSDimitry Andric if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) 59868d75effSDimitry Andric return 0; 59968d75effSDimitry Andric 60068d75effSDimitry Andric // The layout at e_lfanew is: 60168d75effSDimitry Andric // "PE\0\0" 60268d75effSDimitry Andric // IMAGE_FILE_HEADER 60368d75effSDimitry Andric // IMAGE_OPTIONAL_HEADER 60468d75effSDimitry Andric // Seek to e_lfanew and read all that data. 60568d75effSDimitry Andric if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == 60668d75effSDimitry Andric INVALID_SET_FILE_POINTER) 60768d75effSDimitry Andric return 0; 608fe6060f1SDimitry Andric if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size) 60968d75effSDimitry Andric return 0; 61068d75effSDimitry Andric 61168d75effSDimitry Andric // Check for "PE\0\0" before the PE header. 61268d75effSDimitry Andric char *pe_sig = &buf[0]; 61368d75effSDimitry Andric if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) 61468d75effSDimitry Andric return 0; 61568d75effSDimitry Andric 61668d75effSDimitry Andric // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. 61768d75effSDimitry Andric IMAGE_OPTIONAL_HEADER *pe_header = 61868d75effSDimitry Andric (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); 61968d75effSDimitry Andric 62068d75effSDimitry Andric // Check for more magic in the PE header. 62168d75effSDimitry Andric if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) 62268d75effSDimitry Andric return 0; 62368d75effSDimitry Andric 62468d75effSDimitry Andric // Finally, return the ImageBase. 62568d75effSDimitry Andric return (uptr)pe_header->ImageBase; 62668d75effSDimitry Andric } 62768d75effSDimitry Andric 62868d75effSDimitry Andric void ListOfModules::init() { 62968d75effSDimitry Andric clearOrInit(); 63068d75effSDimitry Andric HANDLE cur_process = GetCurrentProcess(); 63168d75effSDimitry Andric 63268d75effSDimitry Andric // Query the list of modules. Start by assuming there are no more than 256 63368d75effSDimitry Andric // modules and retry if that's not sufficient. 63468d75effSDimitry Andric HMODULE *hmodules = 0; 63568d75effSDimitry Andric uptr modules_buffer_size = sizeof(HMODULE) * 256; 63668d75effSDimitry Andric DWORD bytes_required; 63768d75effSDimitry Andric while (!hmodules) { 63868d75effSDimitry Andric hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); 63968d75effSDimitry Andric CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, 64068d75effSDimitry Andric &bytes_required)); 64168d75effSDimitry Andric if (bytes_required > modules_buffer_size) { 64268d75effSDimitry Andric // Either there turned out to be more than 256 hmodules, or new hmodules 64368d75effSDimitry Andric // could have loaded since the last try. Retry. 64468d75effSDimitry Andric UnmapOrDie(hmodules, modules_buffer_size); 64568d75effSDimitry Andric hmodules = 0; 64668d75effSDimitry Andric modules_buffer_size = bytes_required; 64768d75effSDimitry Andric } 64868d75effSDimitry Andric } 64968d75effSDimitry Andric 650fe6060f1SDimitry Andric InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) + 651fe6060f1SDimitry Andric sizeof(IMAGE_OPTIONAL_HEADER)); 652fe6060f1SDimitry Andric InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength); 653fe6060f1SDimitry Andric InternalMmapVector<char> module_name(kMaxPathLength); 65468d75effSDimitry Andric // |num_modules| is the number of modules actually present, 65568d75effSDimitry Andric size_t num_modules = bytes_required / sizeof(HMODULE); 65668d75effSDimitry Andric for (size_t i = 0; i < num_modules; ++i) { 65768d75effSDimitry Andric HMODULE handle = hmodules[i]; 65868d75effSDimitry Andric MODULEINFO mi; 65968d75effSDimitry Andric if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) 66068d75effSDimitry Andric continue; 66168d75effSDimitry Andric 66268d75effSDimitry Andric // Get the UTF-16 path and convert to UTF-8. 66368d75effSDimitry Andric int modname_utf16_len = 664fe6060f1SDimitry Andric GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength); 66568d75effSDimitry Andric if (modname_utf16_len == 0) 66668d75effSDimitry Andric modname_utf16[0] = '\0'; 667fe6060f1SDimitry Andric int module_name_len = ::WideCharToMultiByte( 668fe6060f1SDimitry Andric CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0], 669fe6060f1SDimitry Andric kMaxPathLength, NULL, NULL); 67068d75effSDimitry Andric module_name[module_name_len] = '\0'; 67168d75effSDimitry Andric 67268d75effSDimitry Andric uptr base_address = (uptr)mi.lpBaseOfDll; 67368d75effSDimitry Andric uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; 67468d75effSDimitry Andric 67568d75effSDimitry Andric // Adjust the base address of the module so that we get a VA instead of an 67668d75effSDimitry Andric // RVA when computing the module offset. This helps llvm-symbolizer find the 67768d75effSDimitry Andric // right DWARF CU. In the common case that the image is loaded at it's 67868d75effSDimitry Andric // preferred address, we will now print normal virtual addresses. 679fe6060f1SDimitry Andric uptr preferred_base = 680fe6060f1SDimitry Andric GetPreferredBase(&module_name[0], &buf[0], buf.size()); 68168d75effSDimitry Andric uptr adjusted_base = base_address - preferred_base; 68268d75effSDimitry Andric 683fe6060f1SDimitry Andric modules_.push_back(LoadedModule()); 684fe6060f1SDimitry Andric LoadedModule &cur_module = modules_.back(); 685fe6060f1SDimitry Andric cur_module.set(&module_name[0], adjusted_base); 68668d75effSDimitry Andric // We add the whole module as one single address range. 68768d75effSDimitry Andric cur_module.addAddressRange(base_address, end_address, /*executable*/ true, 68868d75effSDimitry Andric /*writable*/ true); 68968d75effSDimitry Andric } 69068d75effSDimitry Andric UnmapOrDie(hmodules, modules_buffer_size); 69168d75effSDimitry Andric } 69268d75effSDimitry Andric 69368d75effSDimitry Andric void ListOfModules::fallbackInit() { clear(); } 69468d75effSDimitry Andric 69568d75effSDimitry Andric // We can't use atexit() directly at __asan_init time as the CRT is not fully 69668d75effSDimitry Andric // initialized at this point. Place the functions into a vector and use 69768d75effSDimitry Andric // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). 69868d75effSDimitry Andric InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; 69968d75effSDimitry Andric 70068d75effSDimitry Andric int Atexit(void (*function)(void)) { 70168d75effSDimitry Andric atexit_functions.push_back(function); 70268d75effSDimitry Andric return 0; 70368d75effSDimitry Andric } 70468d75effSDimitry Andric 70568d75effSDimitry Andric static int RunAtexit() { 70668d75effSDimitry Andric TraceLoggingUnregister(g_asan_provider); 70768d75effSDimitry Andric int ret = 0; 70868d75effSDimitry Andric for (uptr i = 0; i < atexit_functions.size(); ++i) { 70968d75effSDimitry Andric ret |= atexit(atexit_functions[i]); 71068d75effSDimitry Andric } 71168d75effSDimitry Andric return ret; 71268d75effSDimitry Andric } 71368d75effSDimitry Andric 71468d75effSDimitry Andric #pragma section(".CRT$XID", long, read) 71568d75effSDimitry Andric __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; 71668d75effSDimitry Andric #endif 71768d75effSDimitry Andric 71868d75effSDimitry Andric // ------------------ sanitizer_libc.h 71968d75effSDimitry Andric fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { 72068d75effSDimitry Andric // FIXME: Use the wide variants to handle Unicode filenames. 72168d75effSDimitry Andric fd_t res; 72268d75effSDimitry Andric if (mode == RdOnly) { 72368d75effSDimitry Andric res = CreateFileA(filename, GENERIC_READ, 72468d75effSDimitry Andric FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 72568d75effSDimitry Andric nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 72668d75effSDimitry Andric } else if (mode == WrOnly) { 72768d75effSDimitry Andric res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 72868d75effSDimitry Andric FILE_ATTRIBUTE_NORMAL, nullptr); 72968d75effSDimitry Andric } else { 73068d75effSDimitry Andric UNIMPLEMENTED(); 73168d75effSDimitry Andric } 73268d75effSDimitry Andric CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); 73368d75effSDimitry Andric CHECK(res != kStderrFd || kStderrFd == kInvalidFd); 73468d75effSDimitry Andric if (res == kInvalidFd && last_error) 73568d75effSDimitry Andric *last_error = GetLastError(); 73668d75effSDimitry Andric return res; 73768d75effSDimitry Andric } 73868d75effSDimitry Andric 73968d75effSDimitry Andric void CloseFile(fd_t fd) { 74068d75effSDimitry Andric CloseHandle(fd); 74168d75effSDimitry Andric } 74268d75effSDimitry Andric 74368d75effSDimitry Andric bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 74468d75effSDimitry Andric error_t *error_p) { 74568d75effSDimitry Andric CHECK(fd != kInvalidFd); 74668d75effSDimitry Andric 74768d75effSDimitry Andric // bytes_read can't be passed directly to ReadFile: 74868d75effSDimitry Andric // uptr is unsigned long long on 64-bit Windows. 74968d75effSDimitry Andric unsigned long num_read_long; 75068d75effSDimitry Andric 75168d75effSDimitry Andric bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); 75268d75effSDimitry Andric if (!success && error_p) 75368d75effSDimitry Andric *error_p = GetLastError(); 75468d75effSDimitry Andric if (bytes_read) 75568d75effSDimitry Andric *bytes_read = num_read_long; 75668d75effSDimitry Andric return success; 75768d75effSDimitry Andric } 75868d75effSDimitry Andric 75968d75effSDimitry Andric bool SupportsColoredOutput(fd_t fd) { 76068d75effSDimitry Andric // FIXME: support colored output. 76168d75effSDimitry Andric return false; 76268d75effSDimitry Andric } 76368d75effSDimitry Andric 76468d75effSDimitry Andric bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 76568d75effSDimitry Andric error_t *error_p) { 76668d75effSDimitry Andric CHECK(fd != kInvalidFd); 76768d75effSDimitry Andric 76868d75effSDimitry Andric // Handle null optional parameters. 76968d75effSDimitry Andric error_t dummy_error; 77068d75effSDimitry Andric error_p = error_p ? error_p : &dummy_error; 77168d75effSDimitry Andric uptr dummy_bytes_written; 77268d75effSDimitry Andric bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; 77368d75effSDimitry Andric 77468d75effSDimitry Andric // Initialize output parameters in case we fail. 77568d75effSDimitry Andric *error_p = 0; 77668d75effSDimitry Andric *bytes_written = 0; 77768d75effSDimitry Andric 77868d75effSDimitry Andric // Map the conventional Unix fds 1 and 2 to Windows handles. They might be 77968d75effSDimitry Andric // closed, in which case this will fail. 78068d75effSDimitry Andric if (fd == kStdoutFd || fd == kStderrFd) { 78168d75effSDimitry Andric fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); 78268d75effSDimitry Andric if (fd == 0) { 78368d75effSDimitry Andric *error_p = ERROR_INVALID_HANDLE; 78468d75effSDimitry Andric return false; 78568d75effSDimitry Andric } 78668d75effSDimitry Andric } 78768d75effSDimitry Andric 78868d75effSDimitry Andric DWORD bytes_written_32; 78968d75effSDimitry Andric if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { 79068d75effSDimitry Andric *error_p = GetLastError(); 79168d75effSDimitry Andric return false; 79268d75effSDimitry Andric } else { 79368d75effSDimitry Andric *bytes_written = bytes_written_32; 79468d75effSDimitry Andric return true; 79568d75effSDimitry Andric } 79668d75effSDimitry Andric } 79768d75effSDimitry Andric 79868d75effSDimitry Andric uptr internal_sched_yield() { 79968d75effSDimitry Andric Sleep(0); 80068d75effSDimitry Andric return 0; 80168d75effSDimitry Andric } 80268d75effSDimitry Andric 80368d75effSDimitry Andric void internal__exit(int exitcode) { 80468d75effSDimitry Andric TraceLoggingUnregister(g_asan_provider); 80568d75effSDimitry Andric // ExitProcess runs some finalizers, so use TerminateProcess to avoid that. 80668d75effSDimitry Andric // The debugger doesn't stop on TerminateProcess like it does on ExitProcess, 80768d75effSDimitry Andric // so add our own breakpoint here. 80868d75effSDimitry Andric if (::IsDebuggerPresent()) 80968d75effSDimitry Andric __debugbreak(); 81068d75effSDimitry Andric TerminateProcess(GetCurrentProcess(), exitcode); 81168d75effSDimitry Andric BUILTIN_UNREACHABLE(); 81268d75effSDimitry Andric } 81368d75effSDimitry Andric 81468d75effSDimitry Andric uptr internal_ftruncate(fd_t fd, uptr size) { 81568d75effSDimitry Andric UNIMPLEMENTED(); 81668d75effSDimitry Andric } 81768d75effSDimitry Andric 81868d75effSDimitry Andric uptr GetRSS() { 81968d75effSDimitry Andric PROCESS_MEMORY_COUNTERS counters; 82068d75effSDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) 82168d75effSDimitry Andric return 0; 82268d75effSDimitry Andric return counters.WorkingSetSize; 82368d75effSDimitry Andric } 82468d75effSDimitry Andric 8255ffd83dbSDimitry Andric void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } 82668d75effSDimitry Andric void internal_join_thread(void *th) { } 82768d75effSDimitry Andric 828fe6060f1SDimitry Andric void FutexWait(atomic_uint32_t *p, u32 cmp) { 829fe6060f1SDimitry Andric WaitOnAddress(p, &cmp, sizeof(cmp), INFINITE); 830fe6060f1SDimitry Andric } 831fe6060f1SDimitry Andric 832fe6060f1SDimitry Andric void FutexWake(atomic_uint32_t *p, u32 count) { 833fe6060f1SDimitry Andric if (count == 1) 834fe6060f1SDimitry Andric WakeByAddressSingle(p); 835fe6060f1SDimitry Andric else 836fe6060f1SDimitry Andric WakeByAddressAll(p); 837fe6060f1SDimitry Andric } 838fe6060f1SDimitry Andric 83968d75effSDimitry Andric uptr GetTlsSize() { 84068d75effSDimitry Andric return 0; 84168d75effSDimitry Andric } 84268d75effSDimitry Andric 84368d75effSDimitry Andric void InitTlsSize() { 84468d75effSDimitry Andric } 84568d75effSDimitry Andric 84668d75effSDimitry Andric void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 84768d75effSDimitry Andric uptr *tls_addr, uptr *tls_size) { 84868d75effSDimitry Andric #if SANITIZER_GO 84968d75effSDimitry Andric *stk_addr = 0; 85068d75effSDimitry Andric *stk_size = 0; 85168d75effSDimitry Andric *tls_addr = 0; 85268d75effSDimitry Andric *tls_size = 0; 85368d75effSDimitry Andric #else 85468d75effSDimitry Andric uptr stack_top, stack_bottom; 85568d75effSDimitry Andric GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 85668d75effSDimitry Andric *stk_addr = stack_bottom; 85768d75effSDimitry Andric *stk_size = stack_top - stack_bottom; 85868d75effSDimitry Andric *tls_addr = 0; 85968d75effSDimitry Andric *tls_size = 0; 86068d75effSDimitry Andric #endif 86168d75effSDimitry Andric } 86268d75effSDimitry Andric 86368d75effSDimitry Andric void ReportFile::Write(const char *buffer, uptr length) { 86468d75effSDimitry Andric SpinMutexLock l(mu); 86568d75effSDimitry Andric ReopenIfNecessary(); 86668d75effSDimitry Andric if (!WriteToFile(fd, buffer, length)) { 86768d75effSDimitry Andric // stderr may be closed, but we may be able to print to the debugger 86868d75effSDimitry Andric // instead. This is the case when launching a program from Visual Studio, 86968d75effSDimitry Andric // and the following routine should write to its console. 87068d75effSDimitry Andric OutputDebugStringA(buffer); 87168d75effSDimitry Andric } 87268d75effSDimitry Andric } 87368d75effSDimitry Andric 87468d75effSDimitry Andric void SetAlternateSignalStack() { 87568d75effSDimitry Andric // FIXME: Decide what to do on Windows. 87668d75effSDimitry Andric } 87768d75effSDimitry Andric 87868d75effSDimitry Andric void UnsetAlternateSignalStack() { 87968d75effSDimitry Andric // FIXME: Decide what to do on Windows. 88068d75effSDimitry Andric } 88168d75effSDimitry Andric 88268d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) { 88368d75effSDimitry Andric (void)handler; 88468d75effSDimitry Andric // FIXME: Decide what to do on Windows. 88568d75effSDimitry Andric } 88668d75effSDimitry Andric 88768d75effSDimitry Andric HandleSignalMode GetHandleSignalMode(int signum) { 88868d75effSDimitry Andric // FIXME: Decide what to do on Windows. 88968d75effSDimitry Andric return kHandleSignalNo; 89068d75effSDimitry Andric } 89168d75effSDimitry Andric 89268d75effSDimitry Andric // Check based on flags if we should handle this exception. 89368d75effSDimitry Andric bool IsHandledDeadlyException(DWORD exceptionCode) { 89468d75effSDimitry Andric switch (exceptionCode) { 89568d75effSDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 89668d75effSDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 89768d75effSDimitry Andric case EXCEPTION_STACK_OVERFLOW: 89868d75effSDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 89968d75effSDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 90068d75effSDimitry Andric return common_flags()->handle_segv; 90168d75effSDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 90268d75effSDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 90368d75effSDimitry Andric case EXCEPTION_BREAKPOINT: 90468d75effSDimitry Andric return common_flags()->handle_sigill; 90568d75effSDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 90668d75effSDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 90768d75effSDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 90868d75effSDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 90968d75effSDimitry Andric case EXCEPTION_FLT_OVERFLOW: 91068d75effSDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 91168d75effSDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 91268d75effSDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 91368d75effSDimitry Andric case EXCEPTION_INT_OVERFLOW: 91468d75effSDimitry Andric return common_flags()->handle_sigfpe; 91568d75effSDimitry Andric } 91668d75effSDimitry Andric return false; 91768d75effSDimitry Andric } 91868d75effSDimitry Andric 91968d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) { 92068d75effSDimitry Andric SYSTEM_INFO si; 92168d75effSDimitry Andric GetNativeSystemInfo(&si); 92268d75effSDimitry Andric uptr page_size = si.dwPageSize; 92368d75effSDimitry Andric uptr page_mask = ~(page_size - 1); 92468d75effSDimitry Andric 92568d75effSDimitry Andric for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; 92668d75effSDimitry Andric page <= end;) { 92768d75effSDimitry Andric MEMORY_BASIC_INFORMATION info; 92868d75effSDimitry Andric if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) 92968d75effSDimitry Andric return false; 93068d75effSDimitry Andric 93168d75effSDimitry Andric if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || 93268d75effSDimitry Andric info.Protect == PAGE_EXECUTE) 93368d75effSDimitry Andric return false; 93468d75effSDimitry Andric 93568d75effSDimitry Andric if (info.RegionSize == 0) 93668d75effSDimitry Andric return false; 93768d75effSDimitry Andric 93868d75effSDimitry Andric page += info.RegionSize; 93968d75effSDimitry Andric } 94068d75effSDimitry Andric 94168d75effSDimitry Andric return true; 94268d75effSDimitry Andric } 94368d75effSDimitry Andric 94468d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { 94568d75effSDimitry Andric return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW; 94668d75effSDimitry Andric } 94768d75effSDimitry Andric 94868d75effSDimitry Andric void SignalContext::InitPcSpBp() { 94968d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 95068d75effSDimitry Andric CONTEXT *context_record = (CONTEXT *)context; 95168d75effSDimitry Andric 95268d75effSDimitry Andric pc = (uptr)exception_record->ExceptionAddress; 953*04eeddc0SDimitry Andric # if SANITIZER_WINDOWS64 954*04eeddc0SDimitry Andric # if SANITIZER_ARM64 955*04eeddc0SDimitry Andric bp = (uptr)context_record->Fp; 956*04eeddc0SDimitry Andric sp = (uptr)context_record->Sp; 957*04eeddc0SDimitry Andric # else 95868d75effSDimitry Andric bp = (uptr)context_record->Rbp; 95968d75effSDimitry Andric sp = (uptr)context_record->Rsp; 960*04eeddc0SDimitry Andric # endif 96168d75effSDimitry Andric # else 96268d75effSDimitry Andric bp = (uptr)context_record->Ebp; 96368d75effSDimitry Andric sp = (uptr)context_record->Esp; 96468d75effSDimitry Andric # endif 96568d75effSDimitry Andric } 96668d75effSDimitry Andric 96768d75effSDimitry Andric uptr SignalContext::GetAddress() const { 96868d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 969e8d8bef9SDimitry Andric if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) 97068d75effSDimitry Andric return exception_record->ExceptionInformation[1]; 971e8d8bef9SDimitry Andric return (uptr)exception_record->ExceptionAddress; 97268d75effSDimitry Andric } 97368d75effSDimitry Andric 97468d75effSDimitry Andric bool SignalContext::IsMemoryAccess() const { 975e8d8bef9SDimitry Andric return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode == 976e8d8bef9SDimitry Andric EXCEPTION_ACCESS_VIOLATION; 97768d75effSDimitry Andric } 97868d75effSDimitry Andric 979e8d8bef9SDimitry Andric bool SignalContext::IsTrueFaultingAddress() const { return true; } 98068d75effSDimitry Andric 98168d75effSDimitry Andric SignalContext::WriteFlag SignalContext::GetWriteFlag() const { 98268d75effSDimitry Andric EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo; 983e8d8bef9SDimitry Andric 984e8d8bef9SDimitry Andric // The write flag is only available for access violation exceptions. 985e8d8bef9SDimitry Andric if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) 986e8d8bef9SDimitry Andric return SignalContext::UNKNOWN; 987e8d8bef9SDimitry Andric 98868d75effSDimitry Andric // The contents of this array are documented at 989e8d8bef9SDimitry Andric // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record 99068d75effSDimitry Andric // The first element indicates read as 0, write as 1, or execute as 8. The 99168d75effSDimitry Andric // second element is the faulting address. 99268d75effSDimitry Andric switch (exception_record->ExceptionInformation[0]) { 99368d75effSDimitry Andric case 0: 99468d75effSDimitry Andric return SignalContext::READ; 99568d75effSDimitry Andric case 1: 99668d75effSDimitry Andric return SignalContext::WRITE; 99768d75effSDimitry Andric case 8: 99868d75effSDimitry Andric return SignalContext::UNKNOWN; 99968d75effSDimitry Andric } 100068d75effSDimitry Andric return SignalContext::UNKNOWN; 100168d75effSDimitry Andric } 100268d75effSDimitry Andric 100368d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { 100468d75effSDimitry Andric // FIXME: Implement this. 100568d75effSDimitry Andric } 100668d75effSDimitry Andric 100768d75effSDimitry Andric int SignalContext::GetType() const { 100868d75effSDimitry Andric return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode; 100968d75effSDimitry Andric } 101068d75effSDimitry Andric 101168d75effSDimitry Andric const char *SignalContext::Describe() const { 101268d75effSDimitry Andric unsigned code = GetType(); 101368d75effSDimitry Andric // Get the string description of the exception if this is a known deadly 101468d75effSDimitry Andric // exception. 101568d75effSDimitry Andric switch (code) { 101668d75effSDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 101768d75effSDimitry Andric return "access-violation"; 101868d75effSDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 101968d75effSDimitry Andric return "array-bounds-exceeded"; 102068d75effSDimitry Andric case EXCEPTION_STACK_OVERFLOW: 102168d75effSDimitry Andric return "stack-overflow"; 102268d75effSDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 102368d75effSDimitry Andric return "datatype-misalignment"; 102468d75effSDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 102568d75effSDimitry Andric return "in-page-error"; 102668d75effSDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 102768d75effSDimitry Andric return "illegal-instruction"; 102868d75effSDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 102968d75effSDimitry Andric return "priv-instruction"; 103068d75effSDimitry Andric case EXCEPTION_BREAKPOINT: 103168d75effSDimitry Andric return "breakpoint"; 103268d75effSDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 103368d75effSDimitry Andric return "flt-denormal-operand"; 103468d75effSDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 103568d75effSDimitry Andric return "flt-divide-by-zero"; 103668d75effSDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 103768d75effSDimitry Andric return "flt-inexact-result"; 103868d75effSDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 103968d75effSDimitry Andric return "flt-invalid-operation"; 104068d75effSDimitry Andric case EXCEPTION_FLT_OVERFLOW: 104168d75effSDimitry Andric return "flt-overflow"; 104268d75effSDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 104368d75effSDimitry Andric return "flt-stack-check"; 104468d75effSDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 104568d75effSDimitry Andric return "flt-underflow"; 104668d75effSDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 104768d75effSDimitry Andric return "int-divide-by-zero"; 104868d75effSDimitry Andric case EXCEPTION_INT_OVERFLOW: 104968d75effSDimitry Andric return "int-overflow"; 105068d75effSDimitry Andric } 105168d75effSDimitry Andric return "unknown exception"; 105268d75effSDimitry Andric } 105368d75effSDimitry Andric 105468d75effSDimitry Andric uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 1055fe6060f1SDimitry Andric if (buf_len == 0) 105668d75effSDimitry Andric return 0; 1057fe6060f1SDimitry Andric 1058fe6060f1SDimitry Andric // Get the UTF-16 path and convert to UTF-8. 1059fe6060f1SDimitry Andric InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength); 1060fe6060f1SDimitry Andric int binname_utf16_len = 1061fe6060f1SDimitry Andric GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength); 1062fe6060f1SDimitry Andric if (binname_utf16_len == 0) { 1063fe6060f1SDimitry Andric buf[0] = '\0'; 1064fe6060f1SDimitry Andric return 0; 1065fe6060f1SDimitry Andric } 1066fe6060f1SDimitry Andric int binary_name_len = 1067fe6060f1SDimitry Andric ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len, 1068fe6060f1SDimitry Andric buf, buf_len, NULL, NULL); 1069fe6060f1SDimitry Andric if ((unsigned)binary_name_len == buf_len) 1070fe6060f1SDimitry Andric --binary_name_len; 1071fe6060f1SDimitry Andric buf[binary_name_len] = '\0'; 1072fe6060f1SDimitry Andric return binary_name_len; 107368d75effSDimitry Andric } 107468d75effSDimitry Andric 107568d75effSDimitry Andric uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { 107668d75effSDimitry Andric return ReadBinaryName(buf, buf_len); 107768d75effSDimitry Andric } 107868d75effSDimitry Andric 107968d75effSDimitry Andric void CheckVMASize() { 108068d75effSDimitry Andric // Do nothing. 108168d75effSDimitry Andric } 108268d75effSDimitry Andric 108368d75effSDimitry Andric void InitializePlatformEarly() { 108468d75effSDimitry Andric // Do nothing. 108568d75effSDimitry Andric } 108668d75effSDimitry Andric 108768d75effSDimitry Andric void MaybeReexec() { 108868d75effSDimitry Andric // No need to re-exec on Windows. 108968d75effSDimitry Andric } 109068d75effSDimitry Andric 109168d75effSDimitry Andric void CheckASLR() { 109268d75effSDimitry Andric // Do nothing 109368d75effSDimitry Andric } 109468d75effSDimitry Andric 109568d75effSDimitry Andric void CheckMPROTECT() { 109668d75effSDimitry Andric // Do nothing 109768d75effSDimitry Andric } 109868d75effSDimitry Andric 109968d75effSDimitry Andric char **GetArgv() { 110068d75effSDimitry Andric // FIXME: Actually implement this function. 110168d75effSDimitry Andric return 0; 110268d75effSDimitry Andric } 110368d75effSDimitry Andric 110468d75effSDimitry Andric char **GetEnviron() { 110568d75effSDimitry Andric // FIXME: Actually implement this function. 110668d75effSDimitry Andric return 0; 110768d75effSDimitry Andric } 110868d75effSDimitry Andric 110968d75effSDimitry Andric pid_t StartSubprocess(const char *program, const char *const argv[], 11105ffd83dbSDimitry Andric const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, 11115ffd83dbSDimitry Andric fd_t stderr_fd) { 111268d75effSDimitry Andric // FIXME: implement on this platform 111368d75effSDimitry Andric // Should be implemented based on 111468d75effSDimitry Andric // SymbolizerProcess::StarAtSymbolizerSubprocess 111568d75effSDimitry Andric // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp. 111668d75effSDimitry Andric return -1; 111768d75effSDimitry Andric } 111868d75effSDimitry Andric 111968d75effSDimitry Andric bool IsProcessRunning(pid_t pid) { 112068d75effSDimitry Andric // FIXME: implement on this platform. 112168d75effSDimitry Andric return false; 112268d75effSDimitry Andric } 112368d75effSDimitry Andric 112468d75effSDimitry Andric int WaitForProcess(pid_t pid) { return -1; } 112568d75effSDimitry Andric 112668d75effSDimitry Andric // FIXME implement on this platform. 1127349cc55cSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {} 112868d75effSDimitry Andric 112968d75effSDimitry Andric void CheckNoDeepBind(const char *filename, int flag) { 113068d75effSDimitry Andric // Do nothing. 113168d75effSDimitry Andric } 113268d75effSDimitry Andric 113368d75effSDimitry Andric // FIXME: implement on this platform. 113468d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) { 113568d75effSDimitry Andric UNIMPLEMENTED(); 113668d75effSDimitry Andric } 113768d75effSDimitry Andric 113868d75effSDimitry Andric u32 GetNumberOfCPUs() { 113968d75effSDimitry Andric SYSTEM_INFO sysinfo = {}; 114068d75effSDimitry Andric GetNativeSystemInfo(&sysinfo); 114168d75effSDimitry Andric return sysinfo.dwNumberOfProcessors; 114268d75effSDimitry Andric } 114368d75effSDimitry Andric 114468d75effSDimitry Andric #if SANITIZER_WIN_TRACE 114568d75effSDimitry Andric // TODO(mcgov): Rename this project-wide to PlatformLogInit 114668d75effSDimitry Andric void AndroidLogInit(void) { 114768d75effSDimitry Andric HRESULT hr = TraceLoggingRegister(g_asan_provider); 114868d75effSDimitry Andric if (!SUCCEEDED(hr)) 114968d75effSDimitry Andric return; 115068d75effSDimitry Andric } 115168d75effSDimitry Andric 115268d75effSDimitry Andric void SetAbortMessage(const char *) {} 115368d75effSDimitry Andric 115468d75effSDimitry Andric void LogFullErrorReport(const char *buffer) { 115568d75effSDimitry Andric if (common_flags()->log_to_syslog) { 115668d75effSDimitry Andric InternalMmapVector<wchar_t> filename; 115768d75effSDimitry Andric DWORD filename_length = 0; 115868d75effSDimitry Andric do { 115968d75effSDimitry Andric filename.resize(filename.size() + 0x100); 116068d75effSDimitry Andric filename_length = 116168d75effSDimitry Andric GetModuleFileNameW(NULL, filename.begin(), filename.size()); 116268d75effSDimitry Andric } while (filename_length >= filename.size()); 116368d75effSDimitry Andric TraceLoggingWrite(g_asan_provider, "AsanReportEvent", 116468d75effSDimitry Andric TraceLoggingValue(filename.begin(), "ExecutableName"), 116568d75effSDimitry Andric TraceLoggingValue(buffer, "AsanReportContents")); 116668d75effSDimitry Andric } 116768d75effSDimitry Andric } 116868d75effSDimitry Andric #endif // SANITIZER_WIN_TRACE 116968d75effSDimitry Andric 1170e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {} 1171e8d8bef9SDimitry Andric 117268d75effSDimitry Andric } // namespace __sanitizer 117368d75effSDimitry Andric 117468d75effSDimitry Andric #endif // _WIN32 1175