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
26 namespace __sanitizer {
27
28 // --------------------- sanitizer_common.h
GetPageSize()29 uptr GetPageSize() {
30 return 1U << 14; // FIXME: is this configurable?
31 }
32
GetMmapGranularity()33 uptr GetMmapGranularity() {
34 return 1U << 16; // FIXME: is this configurable?
35 }
36
FileExists(const char * filename)37 bool FileExists(const char *filename) {
38 UNIMPLEMENTED();
39 }
40
GetPid()41 int GetPid() {
42 return GetProcessId(GetCurrentProcess());
43 }
44
GetThreadSelf()45 uptr GetThreadSelf() {
46 return GetCurrentThreadId();
47 }
48
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)49 void 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
MmapOrDie(uptr size,const char * mem_type)62 void *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
UnmapOrDie(void * addr,uptr size)72 void 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
MmapFixedNoReserve(uptr fixed_addr,uptr size)80 void *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
MmapFixedOrDie(uptr fixed_addr,uptr size)91 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
92 return MmapFixedNoReserve(fixed_addr, size);
93 }
94
Mprotect(uptr fixed_addr,uptr size)95 void *Mprotect(uptr fixed_addr, uptr size) {
96 return VirtualAlloc((LPVOID)fixed_addr, size,
97 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
98 }
99
FlushUnneededShadowMemory(uptr addr,uptr size)100 void 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
MemoryRangeIsAvailable(uptr range_start,uptr range_end)105 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
106 // FIXME: shall we do anything here on Windows?
107 return true;
108 }
109
MapFileToMemory(const char * file_name,uptr * buff_size)110 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
111 UNIMPLEMENTED();
112 }
113
114 static const int kMaxEnvNameLength = 128;
115 static const int kMaxEnvValueLength = 32767;
116
117 namespace {
118
119 struct EnvVariable {
120 char name[kMaxEnvNameLength];
121 char value[kMaxEnvValueLength];
122 };
123
124 } // namespace
125
126 static const int kEnvVariables = 5;
127 static EnvVariable env_vars[kEnvVariables];
128 static int num_env_vars;
129
GetEnv(const char * name)130 const char *GetEnv(const char *name) {
131 // Note: this implementation caches the values of the environment variables
132 // and limits their quantity.
133 for (int i = 0; i < num_env_vars; i++) {
134 if (0 == internal_strcmp(name, env_vars[i].name))
135 return env_vars[i].value;
136 }
137 CHECK_LT(num_env_vars, kEnvVariables);
138 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
139 kMaxEnvValueLength);
140 if (rv > 0 && rv < kMaxEnvValueLength) {
141 CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
142 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
143 num_env_vars++;
144 return env_vars[num_env_vars - 1].value;
145 }
146 return 0;
147 }
148
GetPwd()149 const char *GetPwd() {
150 UNIMPLEMENTED();
151 }
152
GetUid()153 u32 GetUid() {
154 UNIMPLEMENTED();
155 }
156
DumpProcessMap()157 void DumpProcessMap() {
158 UNIMPLEMENTED();
159 }
160
DisableCoreDumper()161 void DisableCoreDumper() {
162 UNIMPLEMENTED();
163 }
164
ReExec()165 void ReExec() {
166 UNIMPLEMENTED();
167 }
168
PrepareForSandboxing()169 void PrepareForSandboxing() {
170 // Nothing here for now.
171 }
172
StackSizeIsUnlimited()173 bool StackSizeIsUnlimited() {
174 UNIMPLEMENTED();
175 }
176
SetStackSizeLimitInBytes(uptr limit)177 void SetStackSizeLimitInBytes(uptr limit) {
178 UNIMPLEMENTED();
179 }
180
SleepForSeconds(int seconds)181 void SleepForSeconds(int seconds) {
182 Sleep(seconds * 1000);
183 }
184
SleepForMillis(int millis)185 void SleepForMillis(int millis) {
186 Sleep(millis);
187 }
188
Abort()189 void Abort() {
190 abort();
191 _exit(-1); // abort is not NORETURN on Windows.
192 }
193
194 #ifndef SANITIZER_GO
Atexit(void (* function)(void))195 int Atexit(void (*function)(void)) {
196 return atexit(function);
197 }
198 #endif
199
200 // ------------------ sanitizer_libc.h
internal_mmap(void * addr,uptr length,int prot,int flags,int fd,u64 offset)201 void *internal_mmap(void *addr, uptr length, int prot, int flags,
202 int fd, u64 offset) {
203 UNIMPLEMENTED();
204 }
205
internal_munmap(void * addr,uptr length)206 int internal_munmap(void *addr, uptr length) {
207 UNIMPLEMENTED();
208 }
209
internal_close(fd_t fd)210 int internal_close(fd_t fd) {
211 UNIMPLEMENTED();
212 }
213
internal_isatty(fd_t fd)214 int internal_isatty(fd_t fd) {
215 return _isatty(fd);
216 }
217
internal_open(const char * filename,int flags)218 fd_t internal_open(const char *filename, int flags) {
219 UNIMPLEMENTED();
220 }
221
internal_open(const char * filename,int flags,u32 mode)222 fd_t internal_open(const char *filename, int flags, u32 mode) {
223 UNIMPLEMENTED();
224 }
225
OpenFile(const char * filename,bool write)226 fd_t OpenFile(const char *filename, bool write) {
227 UNIMPLEMENTED();
228 }
229
internal_read(fd_t fd,void * buf,uptr count)230 uptr internal_read(fd_t fd, void *buf, uptr count) {
231 UNIMPLEMENTED();
232 }
233
internal_write(fd_t fd,const void * buf,uptr count)234 uptr internal_write(fd_t fd, const void *buf, uptr count) {
235 if (fd != kStderrFd)
236 UNIMPLEMENTED();
237 HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
238 if (err == 0)
239 return 0; // FIXME: this might not work on some apps.
240 DWORD ret;
241 if (!WriteFile(err, buf, count, &ret, 0))
242 return 0;
243 return ret;
244 }
245
internal_stat(const char * path,void * buf)246 int internal_stat(const char *path, void *buf) {
247 UNIMPLEMENTED();
248 }
249
internal_lstat(const char * path,void * buf)250 int internal_lstat(const char *path, void *buf) {
251 UNIMPLEMENTED();
252 }
253
internal_fstat(fd_t fd,void * buf)254 int internal_fstat(fd_t fd, void *buf) {
255 UNIMPLEMENTED();
256 }
257
internal_filesize(fd_t fd)258 uptr internal_filesize(fd_t fd) {
259 UNIMPLEMENTED();
260 }
261
internal_dup2(int oldfd,int newfd)262 int internal_dup2(int oldfd, int newfd) {
263 UNIMPLEMENTED();
264 }
265
internal_readlink(const char * path,char * buf,uptr bufsize)266 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
267 UNIMPLEMENTED();
268 }
269
internal_sched_yield()270 int internal_sched_yield() {
271 Sleep(0);
272 return 0;
273 }
274
internal__exit(int exitcode)275 void internal__exit(int exitcode) {
276 _exit(exitcode);
277 }
278
279 // ---------------------- BlockingMutex ---------------- {{{1
280 const uptr LOCK_UNINITIALIZED = 0;
281 const uptr LOCK_READY = (uptr)-1;
282
BlockingMutex(LinkerInitialized li)283 BlockingMutex::BlockingMutex(LinkerInitialized li) {
284 // FIXME: see comments in BlockingMutex::Lock() for the details.
285 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
286
287 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
288 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
289 owner_ = LOCK_READY;
290 }
291
BlockingMutex()292 BlockingMutex::BlockingMutex() {
293 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
294 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
295 owner_ = LOCK_READY;
296 }
297
Lock()298 void BlockingMutex::Lock() {
299 if (owner_ == LOCK_UNINITIALIZED) {
300 // FIXME: hm, global BlockingMutex objects are not initialized?!?
301 // This might be a side effect of the clang+cl+link Frankenbuild...
302 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
303
304 // FIXME: If it turns out the linker doesn't invoke our
305 // constructors, we should probably manually Lock/Unlock all the global
306 // locks while we're starting in one thread to avoid double-init races.
307 }
308 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
309 CHECK_EQ(owner_, LOCK_READY);
310 owner_ = GetThreadSelf();
311 }
312
Unlock()313 void BlockingMutex::Unlock() {
314 CHECK_EQ(owner_, GetThreadSelf());
315 owner_ = LOCK_READY;
316 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
317 }
318
CheckLocked()319 void BlockingMutex::CheckLocked() {
320 CHECK_EQ(owner_, GetThreadSelf());
321 }
322
GetTlsSize()323 uptr GetTlsSize() {
324 return 0;
325 }
326
InitTlsSize()327 void InitTlsSize() {
328 }
329
330 } // namespace __sanitizer
331
332 #endif // _WIN32
333