sanitizer_win.cc revision 1dcd1d9d1c86ab9b728386d261fbebe00b32e097
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===-- sanitizer_win.cc --------------------------------------------------===//
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This file is shared between AddressSanitizer and ThreadSanitizer
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// run-time libraries and implements windows-specific functions from
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sanitizer_libc.h.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_platform.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if SANITIZER_WINDOWS
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WIN32_LEAN_AND_MEAN
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NOGDI
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <io.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_libc.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_mutex.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sanitizer_placement_new.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_stacktrace.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace __sanitizer {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_syscall_generic.inc"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --------------------- sanitizer_common.h
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr GetPageSize() {
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return 1U << 14;  // FIXME: is this configurable?
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr GetMmapGranularity() {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1U << 16;  // FIXME: is this configurable?
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr GetMaxVirtualAddress() {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYSTEM_INFO si;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetSystemInfo(&si);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (uptr)si.lpMaximumApplicationAddress;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FileExists(const char *filename) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr internal_getpid() {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetProcessId(GetCurrentProcess());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In contrast to POSIX, on Windows GetCurrentThreadId()
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns a system-unique identifier.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr GetTid() {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetCurrentThreadId();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr GetThreadSelf() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetTid();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                uptr *stack_bottom) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(stack_top);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(stack_bottom);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MEMORY_BASIC_INFORMATION mbi;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FIXME: is it possible for the stack to not be a single allocation?
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Are these values what ASan expects to get (reserved, not committed;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // including stack guard page) ?
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *stack_bottom = (uptr)mbi.AllocationBase;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *MmapOrDie(uptr size, const char *mem_type) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == 0) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           size, size, mem_type);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK("unable to mmap" && 0);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UnmapOrDie(void *addr, uptr size) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           size, size, addr);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK("unable to unmap" && 0);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but on Win64 it does.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (p == 0)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           size, size, fixed_addr, GetLastError());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MmapFixedNoReserve(fixed_addr, size);
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *Mprotect(uptr fixed_addr, uptr size) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return VirtualAlloc((LPVOID)fixed_addr, size,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FlushUnneededShadowMemory(uptr addr, uptr size) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is almost useless on 32-bits.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FIXME: add madvice-analog when we move to 64-bits.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FIXME: shall we do anything here on Windows?
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *MapFileToMemory(const char *file_name, uptr *buff_size) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxEnvNameLength = 128;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const DWORD kMaxEnvValueLength = 32767;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct EnvVariable {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char name[kMaxEnvNameLength];
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char value[kMaxEnvValueLength];
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kEnvVariables = 5;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static EnvVariable env_vars[kEnvVariables];
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int num_env_vars;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *GetEnv(const char *name) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: this implementation caches the values of the environment variables
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and limits their quantity.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < num_env_vars; i++) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (0 == internal_strcmp(name, env_vars[i].name))
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return env_vars[i].value;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_LT(num_env_vars, kEnvVariables);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     kMaxEnvValueLength);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv > 0 && rv < kMaxEnvValueLength) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_env_vars++;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return env_vars[num_env_vars - 1].value;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char *GetPwd() {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)u32 GetUid() {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DumpProcessMap() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DisableCoreDumper() {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReExec() {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrepareForSandboxing() {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nothing here for now.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StackSizeIsUnlimited() {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetStackSizeLimitInBytes(uptr limit) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNIMPLEMENTED();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
198
199char *FindPathToBinary(const char *name) {
200  UNIMPLEMENTED();
201}
202
203void SleepForSeconds(int seconds) {
204  Sleep(seconds * 1000);
205}
206
207void SleepForMillis(int millis) {
208  Sleep(millis);
209}
210
211u64 NanoTime() {
212  return 0;
213}
214
215void Abort() {
216  abort();
217  _exit(-1);  // abort is not NORETURN on Windows.
218}
219
220#ifndef SANITIZER_GO
221int Atexit(void (*function)(void)) {
222  return atexit(function);
223}
224#endif
225
226// ------------------ sanitizer_libc.h
227uptr internal_mmap(void *addr, uptr length, int prot, int flags,
228                   int fd, u64 offset) {
229  UNIMPLEMENTED();
230}
231
232uptr internal_munmap(void *addr, uptr length) {
233  UNIMPLEMENTED();
234}
235
236uptr internal_close(fd_t fd) {
237  UNIMPLEMENTED();
238}
239
240int internal_isatty(fd_t fd) {
241  return _isatty(fd);
242}
243
244uptr internal_open(const char *filename, int flags) {
245  UNIMPLEMENTED();
246}
247
248uptr internal_open(const char *filename, int flags, u32 mode) {
249  UNIMPLEMENTED();
250}
251
252uptr OpenFile(const char *filename, bool write) {
253  UNIMPLEMENTED();
254}
255
256uptr internal_read(fd_t fd, void *buf, uptr count) {
257  UNIMPLEMENTED();
258}
259
260uptr internal_write(fd_t fd, const void *buf, uptr count) {
261  if (fd != kStderrFd)
262    UNIMPLEMENTED();
263  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
264  if (err == 0)
265    return 0;  // FIXME: this might not work on some apps.
266  DWORD ret;
267  if (!WriteFile(err, buf, count, &ret, 0))
268    return 0;
269  return ret;
270}
271
272uptr internal_stat(const char *path, void *buf) {
273  UNIMPLEMENTED();
274}
275
276uptr internal_lstat(const char *path, void *buf) {
277  UNIMPLEMENTED();
278}
279
280uptr internal_fstat(fd_t fd, void *buf) {
281  UNIMPLEMENTED();
282}
283
284uptr internal_filesize(fd_t fd) {
285  UNIMPLEMENTED();
286}
287
288uptr internal_dup2(int oldfd, int newfd) {
289  UNIMPLEMENTED();
290}
291
292uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
293  UNIMPLEMENTED();
294}
295
296uptr internal_sched_yield() {
297  Sleep(0);
298  return 0;
299}
300
301void internal__exit(int exitcode) {
302  _exit(exitcode);
303}
304
305// ---------------------- BlockingMutex ---------------- {{{1
306const uptr LOCK_UNINITIALIZED = 0;
307const uptr LOCK_READY = (uptr)-1;
308
309BlockingMutex::BlockingMutex(LinkerInitialized li) {
310  // FIXME: see comments in BlockingMutex::Lock() for the details.
311  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
312
313  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
314  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
315  owner_ = LOCK_READY;
316}
317
318BlockingMutex::BlockingMutex() {
319  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
320  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
321  owner_ = LOCK_READY;
322}
323
324void BlockingMutex::Lock() {
325  if (owner_ == LOCK_UNINITIALIZED) {
326    // FIXME: hm, global BlockingMutex objects are not initialized?!?
327    // This might be a side effect of the clang+cl+link Frankenbuild...
328    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
329
330    // FIXME: If it turns out the linker doesn't invoke our
331    // constructors, we should probably manually Lock/Unlock all the global
332    // locks while we're starting in one thread to avoid double-init races.
333  }
334  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
335  CHECK_EQ(owner_, LOCK_READY);
336  owner_ = GetThreadSelf();
337}
338
339void BlockingMutex::Unlock() {
340  CHECK_EQ(owner_, GetThreadSelf());
341  owner_ = LOCK_READY;
342  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
343}
344
345void BlockingMutex::CheckLocked() {
346  CHECK_EQ(owner_, GetThreadSelf());
347}
348
349uptr GetTlsSize() {
350  return 0;
351}
352
353void InitTlsSize() {
354}
355
356void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
357                          uptr *tls_addr, uptr *tls_size) {
358#ifdef SANITIZER_GO
359  *stk_addr = 0;
360  *stk_size = 0;
361  *tls_addr = 0;
362  *tls_size = 0;
363#else
364  uptr stack_top, stack_bottom;
365  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
366  *stk_addr = stack_bottom;
367  *stk_size = stack_top - stack_bottom;
368  *tls_addr = 0;
369  *tls_size = 0;
370#endif
371}
372
373void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
374                   uptr stack_top, uptr stack_bottom, bool fast) {
375  (void)fast;
376  (void)stack_top;
377  (void)stack_bottom;
378  stack->max_size = max_s;
379  void *tmp[kStackTraceMax];
380
381  // FIXME: CaptureStackBackTrace might be too slow for us.
382  // FIXME: Compare with StackWalk64.
383  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
384  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
385  uptr offset = 0;
386  // Skip the RTL frames by searching for the PC in the stacktrace.
387  // FIXME: this doesn't work well for the malloc/free stacks yet.
388  for (uptr i = 0; i < cs_ret; i++) {
389    if (pc != (uptr)tmp[i])
390      continue;
391    offset = i;
392    break;
393  }
394
395  stack->size = cs_ret - offset;
396  for (uptr i = 0; i < stack->size; i++)
397    stack->trace[i] = (uptr)tmp[i + offset];
398}
399
400}  // namespace __sanitizer
401
402#endif  // _WIN32
403