sanitizer_win.cc revision 5a58ef4284194419446d77037441f92d85ab7e4c
1//===-- sanitizer_win.cc --------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements windows-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_platform.h"
16#if SANITIZER_WINDOWS
17
18#define WIN32_LEAN_AND_MEAN
19#define NOGDI
20#include <stdlib.h>
21#include <io.h>
22#include <windows.h>
23
24#include "sanitizer_common.h"
25#include "sanitizer_libc.h"
26#include "sanitizer_mutex.h"
27#include "sanitizer_placement_new.h"
28#include "sanitizer_stacktrace.h"
29
30namespace __sanitizer {
31
32#include "sanitizer_syscall_generic.inc"
33
34// --------------------- sanitizer_common.h
35uptr GetPageSize() {
36  return 1U << 14;  // FIXME: is this configurable?
37}
38
39uptr GetMmapGranularity() {
40  return 1U << 16;  // FIXME: is this configurable?
41}
42
43uptr GetMaxVirtualAddress() {
44  SYSTEM_INFO si;
45  GetSystemInfo(&si);
46  return (uptr)si.lpMaximumApplicationAddress;
47}
48
49bool FileExists(const char *filename) {
50  UNIMPLEMENTED();
51}
52
53uptr internal_getpid() {
54  return GetProcessId(GetCurrentProcess());
55}
56
57// In contrast to POSIX, on Windows GetCurrentThreadId()
58// returns a system-unique identifier.
59uptr GetTid() {
60  return GetCurrentThreadId();
61}
62
63uptr GetThreadSelf() {
64  return GetTid();
65}
66
67void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
68                                uptr *stack_bottom) {
69  CHECK(stack_top);
70  CHECK(stack_bottom);
71  MEMORY_BASIC_INFORMATION mbi;
72  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
73  // FIXME: is it possible for the stack to not be a single allocation?
74  // Are these values what ASan expects to get (reserved, not committed;
75  // including stack guard page) ?
76  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
77  *stack_bottom = (uptr)mbi.AllocationBase;
78}
79
80void *MmapOrDie(uptr size, const char *mem_type) {
81  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
82  if (rv == 0) {
83    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
84           size, size, mem_type);
85    CHECK("unable to mmap" && 0);
86  }
87  return rv;
88}
89
90void UnmapOrDie(void *addr, uptr size) {
91  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
92    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
93           size, size, addr);
94    CHECK("unable to unmap" && 0);
95  }
96}
97
98void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
99  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
100  // but on Win64 it does.
101  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
102      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
103  if (p == 0)
104    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
105           size, size, fixed_addr, GetLastError());
106  return p;
107}
108
109void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
110  return MmapFixedNoReserve(fixed_addr, size);
111}
112
113void *Mprotect(uptr fixed_addr, uptr size) {
114  return VirtualAlloc((LPVOID)fixed_addr, size,
115                      MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
116}
117
118void FlushUnneededShadowMemory(uptr addr, uptr size) {
119  // This is almost useless on 32-bits.
120  // FIXME: add madvice-analog when we move to 64-bits.
121}
122
123bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
124  // FIXME: shall we do anything here on Windows?
125  return true;
126}
127
128void *MapFileToMemory(const char *file_name, uptr *buff_size) {
129  UNIMPLEMENTED();
130}
131
132static const int kMaxEnvNameLength = 128;
133static const DWORD kMaxEnvValueLength = 32767;
134
135namespace {
136
137struct EnvVariable {
138  char name[kMaxEnvNameLength];
139  char value[kMaxEnvValueLength];
140};
141
142}  // namespace
143
144static const int kEnvVariables = 5;
145static EnvVariable env_vars[kEnvVariables];
146static int num_env_vars;
147
148const char *GetEnv(const char *name) {
149  // Note: this implementation caches the values of the environment variables
150  // and limits their quantity.
151  for (int i = 0; i < num_env_vars; i++) {
152    if (0 == internal_strcmp(name, env_vars[i].name))
153      return env_vars[i].value;
154  }
155  CHECK_LT(num_env_vars, kEnvVariables);
156  DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
157                                     kMaxEnvValueLength);
158  if (rv > 0 && rv < kMaxEnvValueLength) {
159    CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
160    internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
161    num_env_vars++;
162    return env_vars[num_env_vars - 1].value;
163  }
164  return 0;
165}
166
167const char *GetPwd() {
168  UNIMPLEMENTED();
169}
170
171u32 GetUid() {
172  UNIMPLEMENTED();
173}
174
175void DumpProcessMap() {
176  UNIMPLEMENTED();
177}
178
179void DisableCoreDumper() {
180  UNIMPLEMENTED();
181}
182
183void ReExec() {
184  UNIMPLEMENTED();
185}
186
187void PrepareForSandboxing() {
188  // Nothing here for now.
189}
190
191bool StackSizeIsUnlimited() {
192  UNIMPLEMENTED();
193}
194
195void SetStackSizeLimitInBytes(uptr limit) {
196  UNIMPLEMENTED();
197}
198
199char *FindPathToBinary(const char *name) {
200  // Nothing here for now.
201  return 0;
202}
203
204void SleepForSeconds(int seconds) {
205  Sleep(seconds * 1000);
206}
207
208void SleepForMillis(int millis) {
209  Sleep(millis);
210}
211
212u64 NanoTime() {
213  return 0;
214}
215
216void Abort() {
217  abort();
218  _exit(-1);  // abort is not NORETURN on Windows.
219}
220
221#ifndef SANITIZER_GO
222int Atexit(void (*function)(void)) {
223  return atexit(function);
224}
225#endif
226
227// ------------------ sanitizer_libc.h
228uptr internal_mmap(void *addr, uptr length, int prot, int flags,
229                   int fd, u64 offset) {
230  UNIMPLEMENTED();
231}
232
233uptr internal_munmap(void *addr, uptr length) {
234  UNIMPLEMENTED();
235}
236
237uptr internal_close(fd_t fd) {
238  UNIMPLEMENTED();
239}
240
241int internal_isatty(fd_t fd) {
242  return _isatty(fd);
243}
244
245uptr internal_open(const char *filename, int flags) {
246  UNIMPLEMENTED();
247}
248
249uptr internal_open(const char *filename, int flags, u32 mode) {
250  UNIMPLEMENTED();
251}
252
253uptr OpenFile(const char *filename, bool write) {
254  UNIMPLEMENTED();
255}
256
257uptr internal_read(fd_t fd, void *buf, uptr count) {
258  UNIMPLEMENTED();
259}
260
261uptr internal_write(fd_t fd, const void *buf, uptr count) {
262  if (fd != kStderrFd)
263    UNIMPLEMENTED();
264  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
265  if (err == 0)
266    return 0;  // FIXME: this might not work on some apps.
267  DWORD ret;
268  if (!WriteFile(err, buf, count, &ret, 0))
269    return 0;
270  return ret;
271}
272
273uptr internal_stat(const char *path, void *buf) {
274  UNIMPLEMENTED();
275}
276
277uptr internal_lstat(const char *path, void *buf) {
278  UNIMPLEMENTED();
279}
280
281uptr internal_fstat(fd_t fd, void *buf) {
282  UNIMPLEMENTED();
283}
284
285uptr internal_filesize(fd_t fd) {
286  UNIMPLEMENTED();
287}
288
289uptr internal_dup2(int oldfd, int newfd) {
290  UNIMPLEMENTED();
291}
292
293uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
294  UNIMPLEMENTED();
295}
296
297uptr internal_sched_yield() {
298  Sleep(0);
299  return 0;
300}
301
302void internal__exit(int exitcode) {
303  _exit(exitcode);
304}
305
306// ---------------------- BlockingMutex ---------------- {{{1
307const uptr LOCK_UNINITIALIZED = 0;
308const uptr LOCK_READY = (uptr)-1;
309
310BlockingMutex::BlockingMutex(LinkerInitialized li) {
311  // FIXME: see comments in BlockingMutex::Lock() for the details.
312  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
313
314  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
315  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
316  owner_ = LOCK_READY;
317}
318
319BlockingMutex::BlockingMutex() {
320  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
321  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
322  owner_ = LOCK_READY;
323}
324
325void BlockingMutex::Lock() {
326  if (owner_ == LOCK_UNINITIALIZED) {
327    // FIXME: hm, global BlockingMutex objects are not initialized?!?
328    // This might be a side effect of the clang+cl+link Frankenbuild...
329    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
330
331    // FIXME: If it turns out the linker doesn't invoke our
332    // constructors, we should probably manually Lock/Unlock all the global
333    // locks while we're starting in one thread to avoid double-init races.
334  }
335  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
336  CHECK_EQ(owner_, LOCK_READY);
337  owner_ = GetThreadSelf();
338}
339
340void BlockingMutex::Unlock() {
341  CHECK_EQ(owner_, GetThreadSelf());
342  owner_ = LOCK_READY;
343  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
344}
345
346void BlockingMutex::CheckLocked() {
347  CHECK_EQ(owner_, GetThreadSelf());
348}
349
350uptr GetTlsSize() {
351  return 0;
352}
353
354void InitTlsSize() {
355}
356
357void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
358                          uptr *tls_addr, uptr *tls_size) {
359#ifdef SANITIZER_GO
360  *stk_addr = 0;
361  *stk_size = 0;
362  *tls_addr = 0;
363  *tls_size = 0;
364#else
365  uptr stack_top, stack_bottom;
366  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
367  *stk_addr = stack_bottom;
368  *stk_size = stack_top - stack_bottom;
369  *tls_addr = 0;
370  *tls_size = 0;
371#endif
372}
373
374void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
375                   uptr stack_top, uptr stack_bottom, bool fast) {
376  (void)fast;
377  (void)stack_top;
378  (void)stack_bottom;
379  stack->max_size = max_s;
380  void *tmp[kStackTraceMax];
381
382  // FIXME: CaptureStackBackTrace might be too slow for us.
383  // FIXME: Compare with StackWalk64.
384  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
385  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
386  uptr offset = 0;
387  // Skip the RTL frames by searching for the PC in the stacktrace.
388  // FIXME: this doesn't work well for the malloc/free stacks yet.
389  for (uptr i = 0; i < cs_ret; i++) {
390    if (pc != (uptr)tmp[i])
391      continue;
392    offset = i;
393    break;
394  }
395
396  stack->size = cs_ret - offset;
397  for (uptr i = 0; i < stack->size; i++)
398    stack->trace[i] = (uptr)tmp[i + offset];
399}
400
401}  // namespace __sanitizer
402
403#endif  // _WIN32
404