aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/sanitizer_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sanitizer_common/sanitizer_win.cc')
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc341
1 files changed, 194 insertions, 147 deletions
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 335cecabe118..d5bbe4565068 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -35,7 +35,9 @@ namespace __sanitizer {
// --------------------- sanitizer_common.h
uptr GetPageSize() {
- return 1U << 14; // FIXME: is this configurable?
+ // FIXME: there is an API for getting the system page size (GetSystemInfo or
+ // GetNativeSystemInfo), but if we use it here we get test failures elsewhere.
+ return 1U << 14;
}
uptr GetMmapGranularity() {
@@ -93,6 +95,9 @@ void *MmapOrDie(uptr size, const char *mem_type) {
}
void UnmapOrDie(void *addr, uptr size) {
+ if (!size || !addr)
+ return;
+
if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
Report("ERROR: %s failed to "
"deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
@@ -101,9 +106,10 @@ void UnmapOrDie(void *addr, uptr size) {
}
}
-void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
+void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
// FIXME: is this really "NoReserve"? On Win32 this does not matter much,
// but on Win64 it does.
+ (void)name; // unsupported
void *p = VirtualAlloc((LPVOID)fixed_addr, size,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (p == 0)
@@ -122,7 +128,8 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
return MmapOrDie(size, mem_type);
}
-void *Mprotect(uptr fixed_addr, uptr size) {
+void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
+ (void)name; // unsupported
void *res = VirtualAlloc((LPVOID)fixed_addr, size,
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
if (res == 0)
@@ -132,6 +139,12 @@ void *Mprotect(uptr fixed_addr, uptr size) {
return res;
}
+bool MprotectNoAccess(uptr addr, uptr size) {
+ DWORD old_protection;
+ return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
+}
+
+
void FlushUnneededShadowMemory(uptr addr, uptr size) {
// This is almost useless on 32-bits.
// FIXME: add madvise-analog when we move to 64-bits.
@@ -157,7 +170,7 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) {
UNIMPLEMENTED();
}
-void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) {
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
UNIMPLEMENTED();
}
@@ -206,76 +219,46 @@ u32 GetUid() {
namespace {
struct ModuleInfo {
- HMODULE handle;
+ const char *filepath;
uptr base_address;
uptr end_address;
};
int CompareModulesBase(const void *pl, const void *pr) {
- const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr;
- if (l.base_address < r.base_address)
+ const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
+ if (l->base_address < r->base_address)
return -1;
- return l.base_address > r.base_address;
+ return l->base_address > r->base_address;
}
} // namespace
#ifndef SANITIZER_GO
void DumpProcessMap() {
Report("Dumping process modules:\n");
- HANDLE cur_process = GetCurrentProcess();
+ InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
+ uptr num_modules =
+ GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
- // Query the list of modules. Start by assuming there are no more than 256
- // modules and retry if that's not sufficient.
- ModuleInfo *modules;
- size_t num_modules;
- {
- HMODULE *hmodules = 0;
- uptr modules_buffer_size = sizeof(HMODULE) * 256;
- DWORD bytes_required;
- while (!hmodules) {
- hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
- CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
- &bytes_required));
- if (bytes_required > modules_buffer_size) {
- // Either there turned out to be more than 256 hmodules, or new hmodules
- // could have loaded since the last try. Retry.
- UnmapOrDie(hmodules, modules_buffer_size);
- hmodules = 0;
- modules_buffer_size = bytes_required;
- }
- }
-
- num_modules = bytes_required / sizeof(HMODULE);
- modules =
- (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__);
- for (size_t i = 0; i < num_modules; ++i) {
- modules[i].handle = hmodules[i];
- MODULEINFO mi;
- if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi)))
- continue;
- modules[i].base_address = (uptr)mi.lpBaseOfDll;
- modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
- }
- UnmapOrDie(hmodules, modules_buffer_size);
+ InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
+ for (size_t i = 0; i < num_modules; ++i) {
+ module_infos[i].filepath = modules[i].full_name();
+ module_infos[i].base_address = modules[i].base_address();
+ module_infos[i].end_address = modules[i].ranges().next()->end;
}
-
- qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase);
+ qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
+ CompareModulesBase);
for (size_t i = 0; i < num_modules; ++i) {
- const ModuleInfo &mi = modules[i];
- char module_name[MAX_PATH];
- bool got_module_name = GetModuleFileNameA(
- mi.handle, module_name, sizeof(module_name));
+ const ModuleInfo &mi = module_infos[i];
if (mi.end_address != 0) {
Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
- got_module_name ? module_name : "[no name]");
- } else if (got_module_name) {
- Printf("\t??\?-??? %s\n", module_name);
+ mi.filepath[0] ? mi.filepath : "[no name]");
+ } else if (mi.filepath[0]) {
+ Printf("\t??\?-??? %s\n", mi.filepath);
} else {
Printf("\t???\n");
}
}
- UnmapOrDie(modules, num_modules * sizeof(ModuleInfo));
}
#endif
@@ -288,8 +271,9 @@ void ReExec() {
}
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
- (void)args;
- // Nothing here for now.
+#if !SANITIZER_GO
+ CovPrepareForSandboxing(args);
+#endif
}
bool StackSizeIsUnlimited() {
@@ -313,6 +297,14 @@ char *FindPathToBinary(const char *name) {
return 0;
}
+bool IsPathSeparator(const char c) {
+ return c == '\\' || c == '/';
+}
+
+bool IsAbsolutePath(const char *path) {
+ UNIMPLEMENTED();
+}
+
void SleepForSeconds(int seconds) {
Sleep(seconds * 1000);
}
@@ -333,117 +325,132 @@ void Abort() {
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter) {
- UNIMPLEMENTED();
-};
-
-#ifndef SANITIZER_GO
-int Atexit(void (*function)(void)) {
- return atexit(function);
-}
-#endif
+ HANDLE cur_process = GetCurrentProcess();
-// ------------------ sanitizer_libc.h
-uptr internal_mmap(void *addr, uptr length, int prot, int flags,
- int fd, u64 offset) {
- UNIMPLEMENTED();
-}
+ // Query the list of modules. Start by assuming there are no more than 256
+ // modules and retry if that's not sufficient.
+ HMODULE *hmodules = 0;
+ uptr modules_buffer_size = sizeof(HMODULE) * 256;
+ DWORD bytes_required;
+ while (!hmodules) {
+ hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
+ CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
+ &bytes_required));
+ if (bytes_required > modules_buffer_size) {
+ // Either there turned out to be more than 256 hmodules, or new hmodules
+ // could have loaded since the last try. Retry.
+ UnmapOrDie(hmodules, modules_buffer_size);
+ hmodules = 0;
+ modules_buffer_size = bytes_required;
+ }
+ }
-uptr internal_munmap(void *addr, uptr length) {
- UNIMPLEMENTED();
-}
+ // |num_modules| is the number of modules actually present,
+ // |count| is the number of modules we return.
+ size_t nun_modules = bytes_required / sizeof(HMODULE),
+ count = 0;
+ for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
+ HMODULE handle = hmodules[i];
+ MODULEINFO mi;
+ if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
+ continue;
-uptr internal_close(fd_t fd) {
- UNIMPLEMENTED();
-}
+ char module_name[MAX_PATH];
+ bool got_module_name =
+ GetModuleFileNameA(handle, module_name, sizeof(module_name));
+ if (!got_module_name)
+ module_name[0] = '\0';
+
+ if (filter && !filter(module_name))
+ continue;
+
+ uptr base_address = (uptr)mi.lpBaseOfDll;
+ uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
+ LoadedModule *cur_module = &modules[count];
+ cur_module->set(module_name, base_address);
+ // We add the whole module as one single address range.
+ cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
+ count++;
+ }
+ UnmapOrDie(hmodules, modules_buffer_size);
-int internal_isatty(fd_t fd) {
- return _isatty(fd);
-}
+ return count;
+};
-uptr internal_open(const char *filename, int flags) {
- UNIMPLEMENTED();
-}
+#ifndef SANITIZER_GO
+// We can't use atexit() directly at __asan_init time as the CRT is not fully
+// initialized at this point. Place the functions into a vector and use
+// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
+InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
-uptr internal_open(const char *filename, int flags, u32 mode) {
- UNIMPLEMENTED();
+int Atexit(void (*function)(void)) {
+ atexit_functions.push_back(function);
+ return 0;
}
-uptr OpenFile(const char *filename, bool write) {
- UNIMPLEMENTED();
+static int RunAtexit() {
+ int ret = 0;
+ for (uptr i = 0; i < atexit_functions.size(); ++i) {
+ ret |= atexit(atexit_functions[i]);
+ }
+ return ret;
}
-uptr internal_read(fd_t fd, void *buf, uptr count) {
- UNIMPLEMENTED();
-}
+#pragma section(".CRT$XID", long, read) // NOLINT
+static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
+#endif
-uptr internal_write(fd_t fd, const void *buf, uptr count) {
- if (fd != kStderrFd)
+// ------------------ sanitizer_libc.h
+fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
+ if (mode != WrOnly)
UNIMPLEMENTED();
-
- static HANDLE output_stream = 0;
- // Abort immediately if we know printing is not possible.
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
-
- // If called for the first time, try to use stderr to output stuff,
- // falling back to stdout if anything goes wrong.
- bool fallback_to_stdout = false;
- if (output_stream == 0) {
- output_stream = GetStdHandle(STD_ERROR_HANDLE);
- // We don't distinguish "no such handle" from error.
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
-
- if (output_stream == INVALID_HANDLE_VALUE) {
- // Retry with stdout?
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream == INVALID_HANDLE_VALUE)
- return 0;
- } else {
- // Successfully got an stderr handle. However, if WriteFile() fails,
- // we can still try to fallback to stdout.
- fallback_to_stdout = true;
- }
- }
-
- DWORD ret;
- if (WriteFile(output_stream, buf, count, &ret, 0))
- return ret;
-
- // Re-try with stdout if using a valid stderr handle fails.
- if (fallback_to_stdout) {
- output_stream = GetStdHandle(STD_OUTPUT_HANDLE);
- if (output_stream == 0)
- output_stream = INVALID_HANDLE_VALUE;
- if (output_stream != INVALID_HANDLE_VALUE)
- return internal_write(fd, buf, count);
- }
- return 0;
+ fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, nullptr);
+ CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
+ CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
+ if (res == kInvalidFd && last_error)
+ *last_error = GetLastError();
+ return res;
}
-uptr internal_stat(const char *path, void *buf) {
- UNIMPLEMENTED();
+void CloseFile(fd_t fd) {
+ CloseHandle(fd);
}
-uptr internal_lstat(const char *path, void *buf) {
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
+ error_t *error_p) {
UNIMPLEMENTED();
}
-uptr internal_fstat(fd_t fd, void *buf) {
- UNIMPLEMENTED();
+bool SupportsColoredOutput(fd_t fd) {
+ // FIXME: support colored output.
+ return false;
}
-uptr internal_filesize(fd_t fd) {
- UNIMPLEMENTED();
-}
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
+ error_t *error_p) {
+ CHECK(fd != kInvalidFd);
-uptr internal_dup2(int oldfd, int newfd) {
- UNIMPLEMENTED();
+ if (fd == kStdoutFd) {
+ fd = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (fd == 0) fd = kInvalidFd;
+ } else if (fd == kStderrFd) {
+ fd = GetStdHandle(STD_ERROR_HANDLE);
+ if (fd == 0) fd = kInvalidFd;
+ }
+
+ DWORD internal_bytes_written;
+ if (fd == kInvalidFd ||
+ WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
+ if (error_p) *error_p = GetLastError();
+ return false;
+ } else {
+ if (bytes_written) *bytes_written = internal_bytes_written;
+ return true;
+ }
}
-uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
+bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
UNIMPLEMENTED();
}
@@ -460,10 +467,6 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
UNIMPLEMENTED();
}
-uptr internal_rename(const char *oldpath, const char *newpath) {
- UNIMPLEMENTED();
-}
-
uptr GetRSS() {
return 0;
}
@@ -587,7 +590,7 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
void ReportFile::Write(const char *buffer, uptr length) {
SpinMutexLock l(mu);
ReopenIfNecessary();
- if (length != internal_write(fd, buffer, length)) {
+ if (!WriteToFile(fd, buffer, length)) {
// stderr may be closed, but we may be able to print to the debugger
// instead. This is the case when launching a program from Visual Studio,
// and the following routine should write to its console.
@@ -614,10 +617,54 @@ bool IsDeadlySignal(int signum) {
}
bool IsAccessibleMemoryRange(uptr beg, uptr size) {
- // FIXME: Actually implement this function.
+ SYSTEM_INFO si;
+ GetNativeSystemInfo(&si);
+ uptr page_size = si.dwPageSize;
+ uptr page_mask = ~(page_size - 1);
+
+ for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask;
+ page <= end;) {
+ MEMORY_BASIC_INFORMATION info;
+ if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info))
+ return false;
+
+ if (info.Protect == 0 || info.Protect == PAGE_NOACCESS ||
+ info.Protect == PAGE_EXECUTE)
+ return false;
+
+ if (info.RegionSize == 0)
+ return false;
+
+ page += info.RegionSize;
+ }
+
return true;
}
+SignalContext SignalContext::Create(void *siginfo, void *context) {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
+ CONTEXT *context_record = (CONTEXT*)context;
+
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context_record->Rbp;
+ uptr sp = (uptr)context_record->Rsp;
+#else
+ uptr bp = (uptr)context_record->Ebp;
+ uptr sp = (uptr)context_record->Esp;
+#endif
+ uptr access_addr = exception_record->ExceptionInformation[1];
+
+ return SignalContext(context, access_addr, pc, sp, bp);
+}
+
+uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+ // FIXME: Actually implement this function.
+ CHECK_GT(buf_len, 0);
+ buf[0] = 0;
+ return 0;
+}
+
} // namespace __sanitizer
#endif // _WIN32