123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- //===-- sanitizer_win.cc --------------------------------------------------===//
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This file is shared between AddressSanitizer and ThreadSanitizer
- // run-time libraries and implements windows-specific functions from
- // sanitizer_libc.h.
- //===----------------------------------------------------------------------===//
- #include "sanitizer_platform.h"
- #if SANITIZER_WINDOWS
- #define WIN32_LEAN_AND_MEAN
- #define NOGDI
- #include <windows.h>
- #include <dbghelp.h>
- #include <io.h>
- #include <stdlib.h>
- #include "sanitizer_common.h"
- #include "sanitizer_libc.h"
- #include "sanitizer_mutex.h"
- #include "sanitizer_placement_new.h"
- #include "sanitizer_stacktrace.h"
- namespace __sanitizer {
- #include "sanitizer_syscall_generic.inc"
- // --------------------- sanitizer_common.h
- uptr GetPageSize() {
- return 1U << 14; // FIXME: is this configurable?
- }
- uptr GetMmapGranularity() {
- return 1U << 16; // FIXME: is this configurable?
- }
- uptr GetMaxVirtualAddress() {
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- return (uptr)si.lpMaximumApplicationAddress;
- }
- bool FileExists(const char *filename) {
- UNIMPLEMENTED();
- }
- uptr internal_getpid() {
- return GetProcessId(GetCurrentProcess());
- }
- // In contrast to POSIX, on Windows GetCurrentThreadId()
- // returns a system-unique identifier.
- uptr GetTid() {
- return GetCurrentThreadId();
- }
- uptr GetThreadSelf() {
- return GetTid();
- }
- #if !SANITIZER_GO
- void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
- uptr *stack_bottom) {
- CHECK(stack_top);
- CHECK(stack_bottom);
- MEMORY_BASIC_INFORMATION mbi;
- CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
- // FIXME: is it possible for the stack to not be a single allocation?
- // Are these values what ASan expects to get (reserved, not committed;
- // including stack guard page) ?
- *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
- *stack_bottom = (uptr)mbi.AllocationBase;
- }
- #endif // #if !SANITIZER_GO
- void *MmapOrDie(uptr size, const char *mem_type) {
- void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (rv == 0) {
- Report("ERROR: %s failed to "
- "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
- SanitizerToolName, size, size, mem_type, GetLastError());
- CHECK("unable to mmap" && 0);
- }
- return rv;
- }
- void UnmapOrDie(void *addr, uptr size) {
- if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
- Report("ERROR: %s failed to "
- "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
- SanitizerToolName, size, size, addr, GetLastError());
- CHECK("unable to unmap" && 0);
- }
- }
- void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
- // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
- // but on Win64 it does.
- void *p = VirtualAlloc((LPVOID)fixed_addr, size,
- MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- if (p == 0)
- Report("ERROR: %s failed to "
- "allocate %p (%zd) bytes at %p (error code: %d)\n",
- SanitizerToolName, size, size, fixed_addr, GetLastError());
- return p;
- }
- void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
- return MmapFixedNoReserve(fixed_addr, size);
- }
- void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
- // FIXME: make this really NoReserve?
- return MmapOrDie(size, mem_type);
- }
- void *Mprotect(uptr fixed_addr, uptr size) {
- return VirtualAlloc((LPVOID)fixed_addr, size,
- MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
- }
- void FlushUnneededShadowMemory(uptr addr, uptr size) {
- // This is almost useless on 32-bits.
- // FIXME: add madvice-analog when we move to 64-bits.
- }
- bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
- // FIXME: shall we do anything here on Windows?
- return true;
- }
- void *MapFileToMemory(const char *file_name, uptr *buff_size) {
- UNIMPLEMENTED();
- }
- void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
- UNIMPLEMENTED();
- }
- static const int kMaxEnvNameLength = 128;
- static const DWORD kMaxEnvValueLength = 32767;
- namespace {
- struct EnvVariable {
- char name[kMaxEnvNameLength];
- char value[kMaxEnvValueLength];
- };
- } // namespace
- static const int kEnvVariables = 5;
- static EnvVariable env_vars[kEnvVariables];
- static int num_env_vars;
- const char *GetEnv(const char *name) {
- // Note: this implementation caches the values of the environment variables
- // and limits their quantity.
- for (int i = 0; i < num_env_vars; i++) {
- if (0 == internal_strcmp(name, env_vars[i].name))
- return env_vars[i].value;
- }
- CHECK_LT(num_env_vars, kEnvVariables);
- DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
- kMaxEnvValueLength);
- if (rv > 0 && rv < kMaxEnvValueLength) {
- CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
- internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
- num_env_vars++;
- return env_vars[num_env_vars - 1].value;
- }
- return 0;
- }
- const char *GetPwd() {
- UNIMPLEMENTED();
- }
- u32 GetUid() {
- UNIMPLEMENTED();
- }
- void DumpProcessMap() {
- UNIMPLEMENTED();
- }
- void DisableCoreDumperIfNecessary() {
- // Do nothing.
- }
- void ReExec() {
- UNIMPLEMENTED();
- }
- void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
- (void)args;
- // Nothing here for now.
- }
- bool StackSizeIsUnlimited() {
- UNIMPLEMENTED();
- }
- void SetStackSizeLimitInBytes(uptr limit) {
- UNIMPLEMENTED();
- }
- bool AddressSpaceIsUnlimited() {
- UNIMPLEMENTED();
- }
- void SetAddressSpaceUnlimited() {
- UNIMPLEMENTED();
- }
- char *FindPathToBinary(const char *name) {
- // Nothing here for now.
- return 0;
- }
- void SleepForSeconds(int seconds) {
- Sleep(seconds * 1000);
- }
- void SleepForMillis(int millis) {
- Sleep(millis);
- }
- u64 NanoTime() {
- return 0;
- }
- void Abort() {
- abort();
- internal__exit(-1); // abort is not NORETURN on Windows.
- }
- uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
- UNIMPLEMENTED();
- };
- #ifndef SANITIZER_GO
- int Atexit(void (*function)(void)) {
- return atexit(function);
- }
- #endif
- // ------------------ sanitizer_libc.h
- uptr internal_mmap(void *addr, uptr length, int prot, int flags,
- int fd, u64 offset) {
- UNIMPLEMENTED();
- }
- uptr internal_munmap(void *addr, uptr length) {
- UNIMPLEMENTED();
- }
- uptr internal_close(fd_t fd) {
- UNIMPLEMENTED();
- }
- int internal_isatty(fd_t fd) {
- return _isatty(fd);
- }
- uptr internal_open(const char *filename, int flags) {
- UNIMPLEMENTED();
- }
- uptr internal_open(const char *filename, int flags, u32 mode) {
- UNIMPLEMENTED();
- }
- uptr OpenFile(const char *filename, bool write) {
- UNIMPLEMENTED();
- }
- uptr internal_read(fd_t fd, void *buf, uptr count) {
- UNIMPLEMENTED();
- }
- uptr internal_write(fd_t fd, const void *buf, uptr count) {
- if (fd != kStderrFd)
- UNIMPLEMENTED();
- static HANDLE output_stream = 0;
- // Abort immediately if we know printing is not possible.
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
- // If called for the first time, try to use stderr to output stuff,
- // falling back to stdout if anything goes wrong.
- bool fallback_to_stdout = false;
- if (output_stream == 0) {
- output_stream = GetStdHandle(STD_ERROR_HANDLE);
- // We don't distinguish "no such handle" from error.
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream == INVALID_HANDLE_VALUE) {
- // Retry with stdout?
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
- } else {
- // Successfully got an stderr handle. However, if WriteFile() fails,
- // we can still try to fallback to stdout.
- fallback_to_stdout = true;
- }
- }
- DWORD ret;
- if (WriteFile(output_stream, buf, count, &ret, 0))
- return ret;
- // Re-try with stdout if using a valid stderr handle fails.
- if (fallback_to_stdout) {
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream != INVALID_HANDLE_VALUE)
- return internal_write(fd, buf, count);
- }
- return 0;
- }
- uptr internal_stat(const char *path, void *buf) {
- UNIMPLEMENTED();
- }
- uptr internal_lstat(const char *path, void *buf) {
- UNIMPLEMENTED();
- }
- uptr internal_fstat(fd_t fd, void *buf) {
- UNIMPLEMENTED();
- }
- uptr internal_filesize(fd_t fd) {
- UNIMPLEMENTED();
- }
- uptr internal_dup2(int oldfd, int newfd) {
- UNIMPLEMENTED();
- }
- uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
- UNIMPLEMENTED();
- }
- uptr internal_sched_yield() {
- Sleep(0);
- return 0;
- }
- void internal__exit(int exitcode) {
- ExitProcess(exitcode);
- }
- uptr internal_ftruncate(fd_t fd, uptr size) {
- UNIMPLEMENTED();
- }
- uptr internal_rename(const char *oldpath, const char *newpath) {
- UNIMPLEMENTED();
- }
- // ---------------------- BlockingMutex ---------------- {{{1
- const uptr LOCK_UNINITIALIZED = 0;
- const uptr LOCK_READY = (uptr)-1;
- BlockingMutex::BlockingMutex(LinkerInitialized li) {
- // FIXME: see comments in BlockingMutex::Lock() for the details.
- CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
- }
- BlockingMutex::BlockingMutex() {
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
- }
- void BlockingMutex::Lock() {
- if (owner_ == LOCK_UNINITIALIZED) {
- // FIXME: hm, global BlockingMutex objects are not initialized?!?
- // This might be a side effect of the clang+cl+link Frankenbuild...
- new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
- // FIXME: If it turns out the linker doesn't invoke our
- // constructors, we should probably manually Lock/Unlock all the global
- // locks while we're starting in one thread to avoid double-init races.
- }
- EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- CHECK_EQ(owner_, LOCK_READY);
- owner_ = GetThreadSelf();
- }
- void BlockingMutex::Unlock() {
- CHECK_EQ(owner_, GetThreadSelf());
- owner_ = LOCK_READY;
- LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- }
- void BlockingMutex::CheckLocked() {
- CHECK_EQ(owner_, GetThreadSelf());
- }
- uptr GetTlsSize() {
- return 0;
- }
- void InitTlsSize() {
- }
- void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
- uptr *tls_addr, uptr *tls_size) {
- #ifdef SANITIZER_GO
- *stk_addr = 0;
- *stk_size = 0;
- *tls_addr = 0;
- *tls_size = 0;
- #else
- uptr stack_top, stack_bottom;
- GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
- *stk_addr = stack_bottom;
- *stk_size = stack_top - stack_bottom;
- *tls_addr = 0;
- *tls_size = 0;
- #endif
- }
- #if !SANITIZER_GO
- void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
- CHECK_GE(max_depth, 2);
- // FIXME: CaptureStackBackTrace might be too slow for us.
- // FIXME: Compare with StackWalk64.
- // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
- size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
- (void**)trace, 0);
- if (size == 0)
- return;
- // Skip the RTL frames by searching for the PC in the stacktrace.
- uptr pc_location = LocatePcInTrace(pc);
- PopStackFrames(pc_location);
- }
- void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
- uptr max_depth) {
- CONTEXT ctx = *(CONTEXT *)context;
- STACKFRAME64 stack_frame;
- memset(&stack_frame, 0, sizeof(stack_frame));
- size = 0;
- #if defined(_WIN64)
- int machine_type = IMAGE_FILE_MACHINE_AMD64;
- stack_frame.AddrPC.Offset = ctx.Rip;
- stack_frame.AddrFrame.Offset = ctx.Rbp;
- stack_frame.AddrStack.Offset = ctx.Rsp;
- #else
- int machine_type = IMAGE_FILE_MACHINE_I386;
- stack_frame.AddrPC.Offset = ctx.Eip;
- stack_frame.AddrFrame.Offset = ctx.Ebp;
- stack_frame.AddrStack.Offset = ctx.Esp;
- #endif
- stack_frame.AddrPC.Mode = AddrModeFlat;
- stack_frame.AddrFrame.Mode = AddrModeFlat;
- stack_frame.AddrStack.Mode = AddrModeFlat;
- while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
- &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
- &SymGetModuleBase64, NULL) &&
- size < Min(max_depth, kStackTraceMax)) {
- trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
- }
- }
- #endif // #if !SANITIZER_GO
- void MaybeOpenReportFile() {
- // Windows doesn't have native fork, and we don't support Cygwin or other
- // environments that try to fake it, so the initial report_fd will always be
- // correct.
- }
- void RawWrite(const char *buffer) {
- uptr length = (uptr)internal_strlen(buffer);
- if (length != internal_write(report_fd, buffer, length)) {
- // stderr may be closed, but we may be able to print to the debugger
- // instead. This is the case when launching a program from Visual Studio,
- // and the following routine should write to its console.
- OutputDebugStringA(buffer);
- }
- }
- void SetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
- }
- void UnsetAlternateSignalStack() {
- // FIXME: Decide what to do on Windows.
- }
- void InstallDeadlySignalHandlers(SignalHandlerType handler) {
- (void)handler;
- // FIXME: Decide what to do on Windows.
- }
- bool IsDeadlySignal(int signum) {
- // FIXME: Decide what to do on Windows.
- return false;
- }
- bool IsAccessibleMemoryRange(uptr beg, uptr size) {
- // FIXME: Actually implement this function.
- return true;
- }
- } // namespace __sanitizer
- #endif // _WIN32
|