sanitizer_win.cc revision 3e0b8ff07e86e0858e016d187d842e97aea2255d
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
221uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
222                      string_predicate_t filter) {
223  UNIMPLEMENTED();
224};
225
226#ifndef SANITIZER_GO
227int Atexit(void (*function)(void)) {
228  return atexit(function);
229}
230#endif
231
232// ------------------ sanitizer_libc.h
233uptr internal_mmap(void *addr, uptr length, int prot, int flags,
234                   int fd, u64 offset) {
235  UNIMPLEMENTED();
236}
237
238uptr internal_munmap(void *addr, uptr length) {
239  UNIMPLEMENTED();
240}
241
242uptr internal_close(fd_t fd) {
243  UNIMPLEMENTED();
244}
245
246int internal_isatty(fd_t fd) {
247  return _isatty(fd);
248}
249
250uptr internal_open(const char *filename, int flags) {
251  UNIMPLEMENTED();
252}
253
254uptr internal_open(const char *filename, int flags, u32 mode) {
255  UNIMPLEMENTED();
256}
257
258uptr OpenFile(const char *filename, bool write) {
259  UNIMPLEMENTED();
260}
261
262uptr internal_read(fd_t fd, void *buf, uptr count) {
263  UNIMPLEMENTED();
264}
265
266uptr internal_write(fd_t fd, const void *buf, uptr count) {
267  if (fd != kStderrFd)
268    UNIMPLEMENTED();
269  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
270  if (err == 0)
271    return 0;  // FIXME: this might not work on some apps.
272  DWORD ret;
273  if (!WriteFile(err, buf, count, &ret, 0))
274    return 0;
275  return ret;
276}
277
278uptr internal_stat(const char *path, void *buf) {
279  UNIMPLEMENTED();
280}
281
282uptr internal_lstat(const char *path, void *buf) {
283  UNIMPLEMENTED();
284}
285
286uptr internal_fstat(fd_t fd, void *buf) {
287  UNIMPLEMENTED();
288}
289
290uptr internal_filesize(fd_t fd) {
291  UNIMPLEMENTED();
292}
293
294uptr internal_dup2(int oldfd, int newfd) {
295  UNIMPLEMENTED();
296}
297
298uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
299  UNIMPLEMENTED();
300}
301
302uptr internal_sched_yield() {
303  Sleep(0);
304  return 0;
305}
306
307void internal__exit(int exitcode) {
308  _exit(exitcode);
309}
310
311// ---------------------- BlockingMutex ---------------- {{{1
312const uptr LOCK_UNINITIALIZED = 0;
313const uptr LOCK_READY = (uptr)-1;
314
315BlockingMutex::BlockingMutex(LinkerInitialized li) {
316  // FIXME: see comments in BlockingMutex::Lock() for the details.
317  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
318
319  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
320  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
321  owner_ = LOCK_READY;
322}
323
324BlockingMutex::BlockingMutex() {
325  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
326  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
327  owner_ = LOCK_READY;
328}
329
330void BlockingMutex::Lock() {
331  if (owner_ == LOCK_UNINITIALIZED) {
332    // FIXME: hm, global BlockingMutex objects are not initialized?!?
333    // This might be a side effect of the clang+cl+link Frankenbuild...
334    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
335
336    // FIXME: If it turns out the linker doesn't invoke our
337    // constructors, we should probably manually Lock/Unlock all the global
338    // locks while we're starting in one thread to avoid double-init races.
339  }
340  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
341  CHECK_EQ(owner_, LOCK_READY);
342  owner_ = GetThreadSelf();
343}
344
345void BlockingMutex::Unlock() {
346  CHECK_EQ(owner_, GetThreadSelf());
347  owner_ = LOCK_READY;
348  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
349}
350
351void BlockingMutex::CheckLocked() {
352  CHECK_EQ(owner_, GetThreadSelf());
353}
354
355uptr GetTlsSize() {
356  return 0;
357}
358
359void InitTlsSize() {
360}
361
362void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
363                          uptr *tls_addr, uptr *tls_size) {
364#ifdef SANITIZER_GO
365  *stk_addr = 0;
366  *stk_size = 0;
367  *tls_addr = 0;
368  *tls_size = 0;
369#else
370  uptr stack_top, stack_bottom;
371  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
372  *stk_addr = stack_bottom;
373  *stk_size = stack_top - stack_bottom;
374  *tls_addr = 0;
375  *tls_size = 0;
376#endif
377}
378
379void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
380                        uptr stack_bottom, bool fast) {
381  (void)fast;
382  (void)stack_top;
383  (void)stack_bottom;
384  void *tmp[kStackTraceMax];
385
386  // FIXME: CaptureStackBackTrace might be too slow for us.
387  // FIXME: Compare with StackWalk64.
388  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
389  uptr cs_ret = CaptureStackBackTrace(1, max_depth, tmp, 0);
390  uptr offset = 0;
391  // Skip the RTL frames by searching for the PC in the stacktrace.
392  // FIXME: this doesn't work well for the malloc/free stacks yet.
393  for (uptr i = 0; i < cs_ret; i++) {
394    if (pc != (uptr)tmp[i])
395      continue;
396    offset = i;
397    break;
398  }
399
400  CopyFrom((uptr*)&tmp[offset], cs_ret - offset);
401}
402
403void MaybeOpenReportFile() {
404  // Windows doesn't have native fork, and we don't support Cygwin or other
405  // environments that try to fake it, so the initial report_fd will always be
406  // correct.
407}
408
409void RawWrite(const char *buffer) {
410  static const char *kRawWriteError =
411      "RawWrite can't output requested buffer!\n";
412  uptr length = (uptr)internal_strlen(buffer);
413  if (length != internal_write(report_fd, buffer, length)) {
414    // stderr may be closed, but we may be able to print to the debugger
415    // instead.  This is the case when launching a program from Visual Studio,
416    // and the following routine should write to its console.
417    OutputDebugStringA(buffer);
418  }
419}
420
421}  // namespace __sanitizer
422
423#endif  // _WIN32
424