forked from OSchip/llvm-project
[asan] The first version of the RTL for Windows, reviewed at http://codereview.appspot.com/5647052
llvm-svn: 150185
This commit is contained in:
parent
bc9bb3f581
commit
7ce3e5bb8e
|
@ -689,6 +689,11 @@ static void Deallocate(uint8_t *ptr, AsanStackTrace *stack) {
|
|||
Describe((uintptr_t)ptr, 1);
|
||||
ShowStatsAndAbort();
|
||||
} else if (m->chunk_state != CHUNK_ALLOCATED) {
|
||||
if (ASAN_WINDOWS) {
|
||||
// FIXME: On Windows there are a few extra "unknown free()s"
|
||||
// from __endstdio, need investigating.
|
||||
return;
|
||||
}
|
||||
Report("ERROR: AddressSanitizer attempting free on address which was not"
|
||||
" malloc()-ed: %p\n", ptr);
|
||||
stack->PrintStack();
|
||||
|
|
|
@ -27,8 +27,12 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#endif // _WIN32
|
||||
# include <pthread.h>
|
||||
#else
|
||||
// FIXME: remove when we start intercepting on Windows. Currently it's needed to
|
||||
// define memset/memcpy intrinsics.
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// FIXME(samsonov): Gradually replace system headers with declarations of
|
||||
|
@ -559,6 +563,13 @@ void InitializeAsanInterceptors() {
|
|||
INTERCEPT_FUNCTION(__cxa_throw);
|
||||
CHECK(INTERCEPT_FUNCTION(pthread_create));
|
||||
|
||||
#ifdef _WIN32
|
||||
// FIXME: We don't intercept properly on Windows yet, so use the original
|
||||
// functions for now.
|
||||
REAL(memcpy) = memcpy;
|
||||
REAL(memset) = memset;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
|
||||
|
|
|
@ -59,6 +59,24 @@ extern "C" void* _ReturnAddress(void);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# define ASAN_LINUX 1
|
||||
#else
|
||||
# define ASAN_LINUX 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ASAN_MAC 1
|
||||
#else
|
||||
# define ASAN_MAC 0
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define ASAN_WINDOWS 1
|
||||
#else
|
||||
# define ASAN_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#if !defined(__has_feature)
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
@ -215,14 +233,21 @@ const size_t kPageSizeBits = 12;
|
|||
const size_t kPageSize = 1UL << kPageSizeBits;
|
||||
|
||||
#ifndef _WIN32
|
||||
const size_t kMmapGranularity = kPageSize;
|
||||
# define GET_CALLER_PC() (uintptr_t)__builtin_return_address(0)
|
||||
# define GET_CURRENT_FRAME() (uintptr_t)__builtin_frame_address(0)
|
||||
#else
|
||||
const size_t kMmapGranularity = 1UL << 16;
|
||||
# define GET_CALLER_PC() (uintptr_t)_ReturnAddress()
|
||||
// CaptureStackBackTrace doesn't need to know BP on Windows.
|
||||
// FIXME: This macro is still used when printing error reports though it's not
|
||||
// clear if the BP value is needed in the ASan reports on Windows.
|
||||
# define GET_CURRENT_FRAME() (uintptr_t)0xDEADBEEF
|
||||
|
||||
# ifndef ASAN_USE_EXTERNAL_SYMBOLIZER
|
||||
# define ASAN_USE_EXTERNAL_SYMBOLIZER __asan::WinSymbolize
|
||||
bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define GET_BP_PC_SP \
|
||||
|
|
|
@ -465,8 +465,8 @@ void __asan_init() {
|
|||
|
||||
{
|
||||
if (kLowShadowBeg != kLowShadowEnd) {
|
||||
// mmap the low shadow plus one page.
|
||||
ReserveShadowMemoryRange(kLowShadowBeg - kPageSize, kLowShadowEnd);
|
||||
// mmap the low shadow plus at least one page.
|
||||
ReserveShadowMemoryRange(kLowShadowBeg - kMmapGranularity, kLowShadowEnd);
|
||||
}
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
//===-- asan_win.cc -------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Windows-specific details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <stdio.h> // FIXME: get rid of this.
|
||||
|
||||
#include <new> // FIXME: temporarily needed for placement new in AsanLock.
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_procmaps.h"
|
||||
#include "asan_thread.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// ---------------------- Memory management ---------------- {{{1
|
||||
void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
|
||||
return VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
|
||||
void *rv = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (rv == NULL)
|
||||
OutOfMemoryMessageAndDie(mem_type, size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
|
||||
return VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
void AsanUnmapOrDie(void *addr, size_t size) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ---------------------- IO ---------------- {{{1
|
||||
size_t AsanWrite(int fd, const void *buf, size_t count) {
|
||||
if (fd != 2)
|
||||
UNIMPLEMENTED();
|
||||
|
||||
// FIXME: use WriteFile instead?
|
||||
return fwrite(buf, 1, count, stderr);
|
||||
}
|
||||
|
||||
// FIXME: Looks like these functions are not needed and are linked in by the
|
||||
// code unreachable on Windows. We should clean this up.
|
||||
int AsanOpenReadonly(const char* filename) {
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t AsanRead(int fd, void *buf, size_t count) {
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AsanClose(int fd) {
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
|
||||
static AsanLock dbghelp_lock(LINKER_INITIALIZED);
|
||||
static bool dbghelp_initialized = false;
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
void AsanThread::SetThreadStackTopAndBottom() {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
CHECK(VirtualQuery(&mbi /* on stack */,
|
||||
&mbi, sizeof(mbi)) != 0);
|
||||
// FIXME: is it possible for the stack to not be a single allocation?
|
||||
// Are these values what ASan expects to get (reserved, not committed;
|
||||
// including stack guard page) ?
|
||||
stack_top_ = (uintptr_t)mbi.BaseAddress + mbi.RegionSize;
|
||||
stack_bottom_ = (uintptr_t)mbi.AllocationBase;
|
||||
}
|
||||
|
||||
void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
|
||||
max_size = max_s;
|
||||
void *tmp[kStackTraceMax];
|
||||
|
||||
// FIXME: CaptureStackBackTrace might be too slow for us.
|
||||
// FIXME: Compare with StackWalk64.
|
||||
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
|
||||
size_t cs_ret = CaptureStackBackTrace(1, max_size, tmp, NULL),
|
||||
offset = 0;
|
||||
// Skip the RTL frames by searching for the PC in the stacktrace.
|
||||
// FIXME: this doesn't work well for the malloc/free stacks yet.
|
||||
for (size_t i = 0; i < cs_ret; i++) {
|
||||
if (pc != (uintptr_t)tmp[i])
|
||||
continue;
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
|
||||
size = cs_ret - offset;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
trace[i] = (uintptr_t)tmp[i + offset];
|
||||
}
|
||||
|
||||
bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) {
|
||||
ScopedLock lock(&dbghelp_lock);
|
||||
if (!dbghelp_initialized) {
|
||||
SymSetOptions(SYMOPT_DEFERRED_LOADS |
|
||||
SYMOPT_UNDNAME |
|
||||
SYMOPT_LOAD_LINES);
|
||||
CHECK(SymInitialize(GetCurrentProcess(), NULL, TRUE));
|
||||
// FIXME: We don't call SymCleanup() on exit yet - should we?
|
||||
dbghelp_initialized = true;
|
||||
}
|
||||
|
||||
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
DWORD64 offset = 0;
|
||||
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
|
||||
(DWORD64)addr, &offset, symbol);
|
||||
if (!got_objname)
|
||||
return false;
|
||||
|
||||
DWORD unused;
|
||||
IMAGEHLP_LINE64 info;
|
||||
info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
|
||||
(DWORD64)addr, &unused, &info);
|
||||
int written = 0;
|
||||
out_buffer[0] = '\0';
|
||||
// FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
|
||||
if (got_fileline) {
|
||||
written += SNPrintf(out_buffer + written, buffer_size - written,
|
||||
" %s %s:%d", symbol->Name,
|
||||
info.FileName, info.LineNumber);
|
||||
} else {
|
||||
written += SNPrintf(out_buffer + written, buffer_size - written,
|
||||
" %s+0x%p", symbol->Name, offset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ---------------------- AsanLock ---------------- {{{1
|
||||
enum LockState {
|
||||
LOCK_UNINITIALIZED = 0,
|
||||
LOCK_READY = -1,
|
||||
};
|
||||
|
||||
AsanLock::AsanLock(LinkerInitialized li) {
|
||||
// FIXME: see comments in AsanLock::Lock() for the details.
|
||||
CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
|
||||
|
||||
CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
|
||||
InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
owner_ = LOCK_READY;
|
||||
}
|
||||
|
||||
void AsanLock::Lock() {
|
||||
if (owner_ == LOCK_UNINITIALIZED) {
|
||||
// FIXME: hm, global AsanLock objects are not initialized?!?
|
||||
// This might be a side effect of the clang+cl+link Frankenbuild...
|
||||
new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1));
|
||||
|
||||
// FIXME: If it turns out the linker doesn't invoke our
|
||||
// constructors, we should probably manually Lock/Unlock all the global
|
||||
// locks while we're starting in one thread to avoid double-init races.
|
||||
}
|
||||
EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
CHECK(owner_ == LOCK_READY);
|
||||
owner_ = GetThreadSelf();
|
||||
}
|
||||
|
||||
void AsanLock::Unlock() {
|
||||
CHECK(owner_ == GetThreadSelf());
|
||||
owner_ = LOCK_READY;
|
||||
LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
static bool tsd_key_inited = false;
|
||||
|
||||
// FIXME: is __declspec enough?
|
||||
static __declspec(thread) void *fake_tsd = NULL;
|
||||
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
// FIXME: we're ignoring the destructor for now.
|
||||
tsd_key_inited = true;
|
||||
}
|
||||
|
||||
void *AsanTSDGet() {
|
||||
CHECK(tsd_key_inited);
|
||||
return fake_tsd;
|
||||
}
|
||||
|
||||
void AsanTSDSet(void *tsd) {
|
||||
CHECK(tsd_key_inited);
|
||||
fake_tsd = tsd;
|
||||
}
|
||||
// }}}
|
||||
|
||||
// ---------------------- Various stuff ---------------- {{{1
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
// FIXME: shall we do anything here on Windows?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AtomicInc(int *a) {
|
||||
return InterlockedExchangeAdd((LONG*)a, 1) + 1;
|
||||
}
|
||||
|
||||
const char* AsanGetEnv(const char* name) {
|
||||
// FIXME: implement.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetPid() {
|
||||
return GetProcessId(GetCurrentProcess());
|
||||
}
|
||||
|
||||
uintptr_t GetThreadSelf() {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
void InstallSignalHandlers() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
void AsanDisableCoreDumper() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void AsanDie() {
|
||||
// FIXME: AsanDie() should be the same on all platforms.
|
||||
if (FLAG_sleep_before_dying) {
|
||||
Report("Sleeping for %d second(s)\n", FLAG_sleep_before_dying);
|
||||
Sleep(FLAG_sleep_before_dying * 1000);
|
||||
}
|
||||
_exit(FLAG_exitcode);
|
||||
}
|
||||
// }}}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // _WIN32
|
Loading…
Reference in New Issue