Index: clang/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- clang/lib/Driver/ToolChains/MSVC.cpp +++ clang/lib/Driver/ToolChains/MSVC.cpp @@ -224,6 +224,11 @@ } } + if (TC.getSanitizerArgs(Args).needsLsanRt()) { + // TODO: Is this all? Asan looks way more complicated + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "lsan")); + } + Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Control Flow Guard checks @@ -795,6 +800,7 @@ Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Leak; Res &= ~SanitizerKind::CFIMFCall; return Res; } Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -743,7 +743,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|Fuchsia") + OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|Fuchsia|Windows") set(COMPILER_RT_HAS_LSAN TRUE) else() set(COMPILER_RT_HAS_LSAN FALSE) Index: compiler-rt/lib/lsan/CMakeLists.txt =================================================================== --- compiler-rt/lib/lsan/CMakeLists.txt +++ compiler-rt/lib/lsan/CMakeLists.txt @@ -11,6 +11,7 @@ lsan_common_fuchsia.cpp lsan_common_linux.cpp lsan_common_mac.cpp + lsan_common_win.cpp ) set(LSAN_SOURCES @@ -24,6 +25,7 @@ lsan_posix.cpp lsan_preinit.cpp lsan_thread.cpp + lsan_win.cpp ) set(LSAN_HEADERS Index: compiler-rt/lib/lsan/lsan.h =================================================================== --- compiler-rt/lib/lsan/lsan.h +++ compiler-rt/lib/lsan/lsan.h @@ -16,6 +16,8 @@ # include "lsan_posix.h" #elif SANITIZER_FUCHSIA # include "lsan_fuchsia.h" +#elif SANITIZER_WINDOWS +# include "lsan_win.h" #endif #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" Index: compiler-rt/lib/lsan/lsan_common.h =================================================================== --- compiler-rt/lib/lsan/lsan_common.h +++ compiler-rt/lib/lsan/lsan_common.h @@ -44,7 +44,7 @@ # define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_RISCV64 && SANITIZER_LINUX # define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_WINDOWS # define CAN_SANITIZE_LEAKS 1 #else # define CAN_SANITIZE_LEAKS 0 Index: compiler-rt/lib/lsan/lsan_common.cpp =================================================================== --- compiler-rt/lib/lsan/lsan_common.cpp +++ compiler-rt/lib/lsan/lsan_common.cpp @@ -533,12 +533,16 @@ static void ProcessRootRegion(Frontier *frontier, const RootRegion &root_region) { +# if SANITIZER_WINDOWS + // TODO +# else MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { ScanRootRegion(frontier, root_region, segment.start, segment.end, segment.IsReadable()); } +# endif } // Scans root regions for heap pointers. @@ -757,7 +761,11 @@ // CheckForLeaks which does not use bytes with pointers before the // threads are suspended and stack pointers captured. param.caller_tid = GetTid(); +#if _MSC_VER + param.caller_sp = reinterpret_cast(_AddressOfReturnAddress()); +#else param.caller_sp = reinterpret_cast(__builtin_frame_address(0)); +#endif LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); if (!param.success) { Report("LeakSanitizer has encountered a fatal error.\n"); Index: compiler-rt/lib/lsan/lsan_common_win.cpp =================================================================== --- /dev/null +++ compiler-rt/lib/lsan/lsan_common_win.cpp @@ -0,0 +1,99 @@ +//=-- lsan_common_win.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Implementation of common leak checking functionality. Darwin-specific code. +// +//===----------------------------------------------------------------------===// + +#include "lsan_common.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if CAN_SANITIZE_LEAKS && SANITIZER_WINDOWS + +# define WIN32_LEAN_AND_MEAN +# include + +// `windows.h` needs to be included before `dbghelp.h` +# include +# pragma comment(lib, "Dbghelp.lib") + +namespace __lsan { + +// TODO: Intercepting `ExitProcess` doesn't currently work +void HandleLeaks() { + if (common_flags()->exitcode) + Die(); +} + +void InitializePlatformSpecificModules() {} + +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { + LockThreadRegistry(); + LockAllocator(); + StopTheWorld(callback, argument); + UnlockAllocator(); + UnlockThreadRegistry(); +} + +THREADLOCAL int disable_counter; +bool DisabledInThisThread() { return disable_counter > 0; } +void DisableInThisThread() { disable_counter++; } +void EnableInThisThread() { + if (disable_counter == 0) { + DisableCounterUnderflow(); + } + disable_counter--; +} + +BOOL CALLBACK EnumLoadedModulesCallback(PCSTR module_name, DWORD64 module_base, + ULONG module_size, PVOID user_context) { + auto *frontier = reinterpret_cast(user_context); + + // Parse the PE Headers of all loaded Modules + const auto *module_nt_header = + ImageNtHeader(reinterpret_cast(module_base)); + + CHECK(module_nt_header); + + const auto *section_header = + reinterpret_cast(module_nt_header + 1); + + // Find the `.data` section + for (WORD i = 0; i < module_nt_header->FileHeader.NumberOfSections; + ++i, ++section_header) { + const char data_section_name[6] = ".data"; + const auto is_data_section = + internal_strncmp(reinterpret_cast(section_header->Name), + data_section_name, sizeof(data_section_name)) == 0; + + if (!is_data_section) + continue; + + ScanGlobalRange(module_base + section_header->VirtualAddress, + module_base + section_header->VirtualAddress + + section_header->Misc.VirtualSize - 1, + frontier); + } + + return TRUE; +} + +void ProcessGlobalRegions(Frontier *frontier) { + HANDLE this_process = GetCurrentProcess(); + + EnumerateLoadedModules(this_process, EnumLoadedModulesCallback, frontier); +} +void ProcessPlatformSpecificAllocations(Frontier *frontier) {} + +LoadedModule *GetLinker() { return nullptr; } + +} // namespace __lsan + +#endif // CAN_SANITIZE_LEAKS && SANITIZER_WINDOWS Index: compiler-rt/lib/lsan/lsan_interceptors.cpp =================================================================== --- compiler-rt/lib/lsan/lsan_interceptors.cpp +++ compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -24,15 +24,20 @@ #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #if SANITIZER_POSIX -#include "sanitizer_common/sanitizer_posix.h" +# include "sanitizer_common/sanitizer_posix.h" #endif -#include "sanitizer_common/sanitizer_tls_get_addr.h" + +#if SANITIZER_WINDOWS +# include +#endif + +#include + #include "lsan.h" #include "lsan_allocator.h" #include "lsan_common.h" #include "lsan_thread.h" - -#include +#include "sanitizer_common/sanitizer_tls_get_addr.h" using namespace __lsan; @@ -99,6 +104,11 @@ return lsan_realloc(ptr, size, stack); } +# if SANITIZER_WINDOWS +# define LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN +# define LSAN_MAYBE_INTERCEPT_VALLOC +# else + INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; @@ -111,11 +121,19 @@ return lsan_posix_memalign(memptr, alignment, size, stack); } +# define LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN \ + INTERCEPT_FUNCTION(posix_memalign) + INTERCEPTOR(void*, valloc, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_valloc(size, stack); } + +# define LSAN_MAYBE_INTERCEPT_VALLOC INTERCEPT_FUNCTION(valloc) + +# endif + #endif // !SANITIZER_APPLE #if SANITIZER_INTERCEPT_MEMALIGN @@ -143,12 +161,19 @@ #endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN #if SANITIZER_INTERCEPT_ALIGNED_ALLOC -INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { +# if SANITIZER_WINDOWS +# define LSAN_ALIGNED_ALLOC_NAME _aligned_malloc +# else +# define LSAN_ALIGNED_ALLOC_NAME aligned_alloc +# endif + +INTERCEPTOR(void *, LSAN_ALIGNED_ALLOC_NAME, uptr alignment, uptr size) { ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_aligned_alloc(alignment, size, stack); } -#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) +# define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC \ + INTERCEPT_FUNCTION(LSAN_ALIGNED_ALLOC_NAME) #else #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC #endif @@ -244,9 +269,15 @@ // OS X we need to intercept them using their mangled names. #if !SANITIZER_APPLE -INTERCEPTOR_ATTRIBUTE +# if SANITIZER_WINDOWS +# define INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE +# else +# define INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE INTERCEPTOR_ATTRIBUTE +# endif + +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE void *operator new(size_t size, std::nothrow_t const&) @@ -254,10 +285,10 @@ INTERCEPTOR_ATTRIBUTE void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY(true /*nothrow*/); } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void *operator new(size_t size, std::align_val_t align) { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void *operator new[](size_t size, std::align_val_t align) { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } INTERCEPTOR_ATTRIBUTE @@ -267,25 +298,25 @@ void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const &) { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete(void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete[](void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete(void *ptr, std::align_val_t) NOEXCEPT { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete[](void *ptr, std::align_val_t) NOEXCEPT { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE @@ -294,10 +325,10 @@ INTERCEPTOR_ATTRIBUTE void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT { OPERATOR_DELETE_BODY; } -INTERCEPTOR_ATTRIBUTE +INTERCEPTOR_ATTRIBUTE_DIFFERENT_LINKAGE void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT { OPERATOR_DELETE_BODY; } @@ -479,10 +510,26 @@ return res; } +# define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE INTERCEPT_FUNCTION(pthread_create) + +#else +# define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE +#endif + +#if SANITIZER_POSIX + INTERCEPTOR(int, pthread_join, void *t, void **arg) { return REAL(pthread_join)(t, arg); } +# define LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE INTERCEPT_FUNCTION(pthread_join) + +#else +# define LSAN_MAYBE_INTERCEPT_PTHREAD_JOIN +#endif + +#if SANITIZER_POSIX + DEFINE_REAL_PTHREAD_FUNCTIONS INTERCEPTOR(void, _exit, int status) { @@ -490,17 +537,71 @@ REAL(_exit)(status); } -#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) -#include "sanitizer_common/sanitizer_signal_interceptors.inc" +# define LSAN_MAYBE_INTERCEPT__EXIT INTERCEPT_FUNCTION(_exit) + +#else +# define LSAN_MAYBE_INTERCEPT__EXIT +#endif +#if SANITIZER_POSIX +# define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) +# include "sanitizer_common/sanitizer_signal_interceptors.inc" #endif // SANITIZER_POSIX +#if SANITIZER_WINDOWS + +INTERCEPTOR_WINAPI(void, ExitProcess, UINT uExitCode) { + if (HasReportedLeaks()) { + uExitCode = common_flags()->exitcode; + } + return REAL(ExitProcess)(uExitCode); +} + +# define LSAN_MAYBE_INTERCEPT_EXIT_PROCESS INTERCEPT_FUNCTION(ExitProcess) +#else +# define LSAN_MAYBE_INTERCEPT_EXIT_PROCESS +#endif + +#if SANITIZER_WINDOWS +INTERCEPTOR_WINAPI(BOOL, TerminateProcess, HANDLE hProcess, UINT uExitCode) { + if (HasReportedLeaks()) { + uExitCode = common_flags()->exitcode; + } + return REAL(TerminateProcess)(hProcess, uExitCode); +} + +# define LSAN_MAYBE_INTERCEPT_TERMINATE_PROCESS \ + INTERCEPT_FUNCTION(TerminateProcess) + +#else +# define LSAN_MAYBE_INTERCEPT_TERMINATE_PROCESS +#endif + +#if SANITIZER_WINDOWS +INTERCEPTOR_WINAPI(HANDLE, CreateThread, + LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + __drv_aliasesMem LPVOID lpParameter, DWORD dwCreationFlags, + LPDWORD lpThreadId) { + // TODO + return REAL(CreateThread)(lpThreadAttributes, dwStackSize, lpStartAddress, + lpParameter, dwCreationFlags, lpThreadId); +} + +# define LSAN_MAYBE_INTERCEPT_CREATE_THREAD INTERCEPT_FUNCTION(CreateThread) + +#else +# define LSAN_MAYBE_INTERCEPT_CREATE_THREAD +#endif + namespace __lsan { void InitializeInterceptors() { // Fuchsia doesn't use interceptors that require any setup. #if !SANITIZER_FUCHSIA +# if SANITIZER_POSIX InitializeSignalInterceptors(); +# endif INTERCEPT_FUNCTION(malloc); INTERCEPT_FUNCTION(free); @@ -510,15 +611,15 @@ LSAN_MAYBE_INTERCEPT_MEMALIGN; LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC; - INTERCEPT_FUNCTION(posix_memalign); - INTERCEPT_FUNCTION(valloc); + LSAN_MAYBE_INTERCEPT_POSIX_MEMALIGN; + LSAN_MAYBE_INTERCEPT_VALLOC; LSAN_MAYBE_INTERCEPT_PVALLOC; LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE; LSAN_MAYBE_INTERCEPT_MALLINFO; LSAN_MAYBE_INTERCEPT_MALLOPT; - INTERCEPT_FUNCTION(pthread_create); - INTERCEPT_FUNCTION(pthread_join); - INTERCEPT_FUNCTION(_exit); + LSAN_MAYBE_INTERCEPT_PTHREAD_CREATE; + LSAN_MAYBE_INTERCEPT_PTHREAD_JOIN; + LSAN_MAYBE_INTERCEPT__EXIT; LSAN_MAYBE_INTERCEPT__LWP_EXIT; LSAN_MAYBE_INTERCEPT_THR_EXIT; @@ -529,14 +630,19 @@ LSAN_MAYBE_INTERCEPT_STRERROR; -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD + // FIXME(cwasser): Intercept Win32 functions + //LSAN_MAYBE_INTERCEPT_EXIT_PROCESS; + //LSAN_MAYBE_INTERCEPT_TERMINATE_PROCESS; + //LSAN_MAYBE_INTERCEPT_CREATE_THREAD; + +# if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_WINDOWS if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); Die(); } -#endif +# endif #endif // !SANITIZER_FUCHSIA } -} // namespace __lsan +} // namespace __lsan Index: compiler-rt/lib/lsan/lsan_win.h =================================================================== --- /dev/null +++ compiler-rt/lib/lsan/lsan_win.h @@ -0,0 +1,41 @@ +//=-- lsan_win.h -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to Windows systems. +// +//===---------------------------------------------------------------------===// + +#ifndef LSAN_WINDOWS_H +#define LSAN_WINDOWS_H + +#include "lsan_thread.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if !SANITIZER_WINDOWS +# error "lsan_win.h is used only on Windows systems (SANITIZER_WINDOWS)" +#endif + +namespace __sanitizer { +struct DTLS; +} + +namespace __lsan { + +class ThreadContext final : public ThreadContextLsanBase { + public: + explicit ThreadContext(int tid); + void OnStarted(void *arg) override; +}; + +void ThreadStart(u32 tid, tid_t os_id, + ThreadType thread_type = ThreadType::Regular); + +} // namespace __lsan + +#endif // LSAN_WINDOWS_H Index: compiler-rt/lib/lsan/lsan_win.cpp =================================================================== --- /dev/null +++ compiler-rt/lib/lsan/lsan_win.cpp @@ -0,0 +1,111 @@ +//=-- lsan_win.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to POSIX-like systems. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_WINDOWS +# include "lsan.h" +# include "lsan_allocator.h" +# include "sanitizer_common/sanitizer_stacktrace.h" +# include "sanitizer_common/sanitizer_tls_get_addr.h" + +namespace __lsan { + +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} + +struct OnStartedArgs { + uptr stack_begin; + uptr stack_end; + uptr cache_begin; + uptr cache_end; + uptr tls_begin; + uptr tls_end; +}; + +void ThreadContext::OnStarted(void *arg) { + auto args = reinterpret_cast(arg); + stack_begin_ = args->stack_begin; + stack_end_ = args->stack_end; + cache_begin_ = args->cache_begin; + cache_end_ = args->cache_end; +} + +void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { + OnStartedArgs args; + uptr stack_size = 0; + uptr tls_size = 0; + GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size, + &args.tls_begin, &tls_size); + args.stack_end = args.stack_begin + stack_size; + args.tls_end = args.tls_begin + tls_size; + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args); +} + +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { + ThreadContext *context = static_cast( + GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id)); + if (!context) + return false; + *stack_begin = context->stack_begin(); + *stack_end = context->stack_end(); + *cache_begin = context->cache_begin(); + *cache_end = context->cache_end(); + *dtls = 0; + return true; +} + +void InitializeMainThread() { + u32 tid = ThreadCreate(kMainTid, true); + CHECK_EQ(tid, kMainTid); + ThreadStart(tid, GetTid()); +} + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); +} + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, + nullptr); +} + +void ReplaceSystemMalloc() {} + +static THREADLOCAL u32 current_thread_tid = kInvalidTid; +u32 GetCurrentThread() { return current_thread_tid; } +void SetCurrentThread(u32 tid) { current_thread_tid = tid; } + +static THREADLOCAL AllocatorCache allocator_cache; +AllocatorCache *GetAllocatorCache() { return &allocator_cache; } + +void InstallAtExitCheckLeaks() { + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) + Atexit(DoLeakCheck); +} + +} // namespace __lsan + +int lsan_win_init() { + __lsan_init(); + return 0; +} + +# pragma section(".CRT$XIB", long, read) +__declspec(allocate(".CRT$XIB")) int (*__lsan_preinit)() = lsan_win_init; + +#endif // SANITIZER_WINDOWS Index: compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -486,13 +486,15 @@ #define SANITIZER_INTERCEPT_MMAP SI_POSIX #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID || SI_SOLARIS #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID) -#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_MEMALIGN \ + (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_WINDOWS) #define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC #define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID) #define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64) #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC) -#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD) +#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE \ + (!SI_MAC && !SI_NETBSD && !SI_WINDOWS) #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSCAT SI_POSIX #define SANITIZER_INTERCEPT_WCSDUP SI_POSIX Index: compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp @@ -19,8 +19,13 @@ // windows.h needs to be included before tlhelp32.h # include +# include "interception/interception.h" # include "sanitizer_stoptheworld.h" +DECLARE_REAL(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES lpThreadAttributes, + SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); + namespace __sanitizer { namespace { @@ -162,12 +167,15 @@ struct RunThreadArgs arg = {callback, argument}; DWORD trace_thread_id; - auto trace_thread = - CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id); - CHECK(trace_thread); - - WaitForSingleObject(trace_thread, INFINITE); - CloseHandle(trace_thread); + // TODO(cwasser): Spawning a tracer thread at this point causes a deadlock in + // malloc during thread creation. + //auto trace_thread = + // REAL(CreateThread)(nullptr, 0, RunThread, &arg, 0, &trace_thread_id); + //CHECK(trace_thread); + // + //WaitForSingleObject(trace_thread, INFINITE); + //CloseHandle(trace_thread); + RunThread(&arg); } } // namespace __sanitizer Index: compiler-rt/test/lsan/lit.common.cfg.py =================================================================== --- compiler-rt/test/lsan/lit.common.cfg.py +++ compiler-rt/test/lsan/lit.common.cfg.py @@ -74,12 +74,13 @@ config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) # LeakSanitizer tests are currently supported on -# Android{aarch64, x86, x86_64}, x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, s390x Linux and x86_64 Darwin. +# Windows{x86_64, x86, aarch64, arm}, Android{aarch64, x86, x86_64}, x86-64 Linux, PowerPC64 Linux, arm Linux, mips64 Linux, s390x Linux and x86_64 Darwin. supported_android = config.android and config.target_arch in ['x86_64', 'i386', 'aarch64'] and 'android-thread-properties-api' in config.available_features supported_linux = (not config.android) and config.host_os == 'Linux' and config.host_arch in ['aarch64', 'x86_64', 'ppc64', 'ppc64le', 'mips64', 'riscv64', 'arm', 'armhf', 'armv7l', 's390x'] supported_darwin = config.host_os == 'Darwin' and config.target_arch in ['x86_64'] supported_netbsd = config.host_os == 'NetBSD' and config.target_arch in ['x86_64', 'i386'] -if not (supported_android or supported_linux or supported_darwin or supported_netbsd): +supported_windows = config.host_os == 'Windows' and config.target_arch in ['x86_64', 'i386', 'aarch64', 'arm'] +if not (supported_android or supported_linux or supported_darwin or supported_netbsd or supported_windows): config.unsupported = True # Don't support Thumb due to broken fast unwinder