sanitizer_win.cc revision 0fa691b7ec97d8c3948a637d6263822ed4e738f7
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#ifdef _WIN32
15#define WIN32_LEAN_AND_MEAN
16#define NOGDI
17#include <stdlib.h>
18#include <io.h>
19#include <windows.h>
20
21#include "sanitizer_common.h"
22#include "sanitizer_libc.h"
23#include "sanitizer_placement_new.h"
24#include "sanitizer_mutex.h"
25
26namespace __sanitizer {
27
28// --------------------- sanitizer_common.h
29uptr GetPageSize() {
30  return 1U << 14;  // FIXME: is this configurable?
31}
32
33uptr GetMmapGranularity() {
34  return 1U << 16;  // FIXME: is this configurable?
35}
36
37bool FileExists(const char *filename) {
38  UNIMPLEMENTED();
39}
40
41int GetPid() {
42  return GetProcessId(GetCurrentProcess());
43}
44
45uptr GetThreadSelf() {
46  return GetCurrentThreadId();
47}
48
49void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
50                                uptr *stack_bottom) {
51  CHECK(stack_top);
52  CHECK(stack_bottom);
53  MEMORY_BASIC_INFORMATION mbi;
54  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
55  // FIXME: is it possible for the stack to not be a single allocation?
56  // Are these values what ASan expects to get (reserved, not committed;
57  // including stack guard page) ?
58  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
59  *stack_bottom = (uptr)mbi.AllocationBase;
60}
61
62void *MmapOrDie(uptr size, const char *mem_type) {
63  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
64  if (rv == 0) {
65    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
66           size, size, mem_type);
67    CHECK("unable to mmap" && 0);
68  }
69  return rv;
70}
71
72void UnmapOrDie(void *addr, uptr size) {
73  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
74    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
75           size, size, addr);
76    CHECK("unable to unmap" && 0);
77  }
78}
79
80void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
81  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
82  // but on Win64 it does.
83  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
84      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
85  if (p == 0)
86    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
87           size, size, fixed_addr, GetLastError());
88  return p;
89}
90
91void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
92  return MmapFixedNoReserve(fixed_addr, size);
93}
94
95void *Mprotect(uptr fixed_addr, uptr size) {
96  return VirtualAlloc((LPVOID)fixed_addr, size,
97                      MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
98}
99
100void FlushUnneededShadowMemory(uptr addr, uptr size) {
101  // This is almost useless on 32-bits.
102  // FIXME: add madvice-analog when we move to 64-bits.
103}
104
105bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
106  // FIXME: shall we do anything here on Windows?
107  return true;
108}
109
110void *MapFileToMemory(const char *file_name, uptr *buff_size) {
111  UNIMPLEMENTED();
112}
113
114const char *GetEnv(const char *name) {
115  static char env_buffer[32767] = {};
116
117  // Note: this implementation stores the result in a static buffer so we only
118  // allow it to be called just once.
119  static bool called_once = false;
120  if (called_once)
121    UNIMPLEMENTED();
122  called_once = true;
123
124  DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer));
125  if (rv > 0 && rv < sizeof(env_buffer))
126    return env_buffer;
127  return 0;
128}
129
130const char *GetPwd() {
131  UNIMPLEMENTED();
132}
133
134u32 GetUid() {
135  UNIMPLEMENTED();
136}
137
138void DumpProcessMap() {
139  UNIMPLEMENTED();
140}
141
142void DisableCoreDumper() {
143  UNIMPLEMENTED();
144}
145
146void ReExec() {
147  UNIMPLEMENTED();
148}
149
150void PrepareForSandboxing() {
151  // Nothing here for now.
152}
153
154bool StackSizeIsUnlimited() {
155  UNIMPLEMENTED();
156}
157
158void SetStackSizeLimitInBytes(uptr limit) {
159  UNIMPLEMENTED();
160}
161
162void SleepForSeconds(int seconds) {
163  Sleep(seconds * 1000);
164}
165
166void SleepForMillis(int millis) {
167  Sleep(millis);
168}
169
170void Exit(int exitcode) {
171  _exit(exitcode);
172}
173
174void Abort() {
175  abort();
176  _exit(-1);  // abort is not NORETURN on Windows.
177}
178
179#ifndef SANITIZER_GO
180int Atexit(void (*function)(void)) {
181  return atexit(function);
182}
183#endif
184
185// ------------------ sanitizer_libc.h
186void *internal_mmap(void *addr, uptr length, int prot, int flags,
187                    int fd, u64 offset) {
188  UNIMPLEMENTED();
189}
190
191int internal_munmap(void *addr, uptr length) {
192  UNIMPLEMENTED();
193}
194
195int internal_close(fd_t fd) {
196  UNIMPLEMENTED();
197}
198
199int internal_isatty(fd_t fd) {
200  return _isatty(fd);
201}
202
203fd_t internal_open(const char *filename, int flags) {
204  UNIMPLEMENTED();
205}
206
207fd_t internal_open(const char *filename, int flags, u32 mode) {
208  UNIMPLEMENTED();
209}
210
211fd_t OpenFile(const char *filename, bool write) {
212  UNIMPLEMENTED();
213}
214
215uptr internal_read(fd_t fd, void *buf, uptr count) {
216  UNIMPLEMENTED();
217}
218
219uptr internal_write(fd_t fd, const void *buf, uptr count) {
220  if (fd != kStderrFd)
221    UNIMPLEMENTED();
222  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
223  if (err == 0)
224    return 0;  // FIXME: this might not work on some apps.
225  DWORD ret;
226  if (!WriteFile(err, buf, count, &ret, 0))
227    return 0;
228  return ret;
229}
230
231int internal_stat(const char *path, void *buf) {
232  UNIMPLEMENTED();
233}
234
235int internal_lstat(const char *path, void *buf) {
236  UNIMPLEMENTED();
237}
238
239int internal_fstat(fd_t fd, void *buf) {
240  UNIMPLEMENTED();
241}
242
243uptr internal_filesize(fd_t fd) {
244  UNIMPLEMENTED();
245}
246
247int internal_dup2(int oldfd, int newfd) {
248  UNIMPLEMENTED();
249}
250
251uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
252  UNIMPLEMENTED();
253}
254
255int internal_sched_yield() {
256  Sleep(0);
257  return 0;
258}
259
260// ---------------------- BlockingMutex ---------------- {{{1
261const uptr LOCK_UNINITIALIZED = 0;
262const uptr LOCK_READY = (uptr)-1;
263
264BlockingMutex::BlockingMutex(LinkerInitialized li) {
265  // FIXME: see comments in BlockingMutex::Lock() for the details.
266  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
267
268  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
269  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
270  owner_ = LOCK_READY;
271}
272
273void BlockingMutex::Lock() {
274  if (owner_ == LOCK_UNINITIALIZED) {
275    // FIXME: hm, global BlockingMutex objects are not initialized?!?
276    // This might be a side effect of the clang+cl+link Frankenbuild...
277    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
278
279    // FIXME: If it turns out the linker doesn't invoke our
280    // constructors, we should probably manually Lock/Unlock all the global
281    // locks while we're starting in one thread to avoid double-init races.
282  }
283  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
284  CHECK_EQ(owner_, LOCK_READY);
285  owner_ = GetThreadSelf();
286}
287
288void BlockingMutex::Unlock() {
289  CHECK_EQ(owner_, GetThreadSelf());
290  owner_ = LOCK_READY;
291  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
292}
293
294}  // namespace __sanitizer
295
296#endif  // _WIN32
297