russell.gallop updated this revision to Diff 312827. russell.gallop edited the summary of this revision. russell.gallop added a comment.
Apologies for the delay, I've had other things taking my time. Latest version uploaded. This fixes stage1 lit tests (on Windows and Linux) and adds scudo_cxx to linking. Usage has changed slightly, now -DLLVM_INTEGRATED_CRT_ALLOC should point to the directory with scudo built libraries (e.g. c:/git/llvm-project/stage1/lib/clang/12.0.0/lib/windows) rather than the library itself. -fsanitize=scudo works for the lit tests (as clang adds the libraries when driving the linker) but doesn't work for building LLVM as cmake links with the linker directly so this uses LLVM_INTEGRATED_CRT_ALLOC. There are two issues I'm aware of now: - Linking c-index-test.exe with scudo fails due to new being redefined lld-link: error: void * __cdecl operator new(unsigned __int64) was replaced Or from link.exe clang_rt.scudo_cxx-x86_64.lib(scudo_new_delete.cpp.obj) : error LNK2005: "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) already defined in libclang.lib(libclang.dll) ... - With scudo all lit tests (generally) pass, but there are some intermittent failures (Access Violation) on the following tests: > ExecutionEngine/MCJIT/test-global-init-nonzero-sm-pic.ll > ExecutionEngine/MCJIT/test-ptr-reloc-sm-pic.ll > ExecutionEngine/MCJIT/multi-module-sm-pic-a.ll This happens with VS2019 or clang-cl as the toolchain. I've run multiple times without scudo and don't see these. Unfortunately I haven't been able to get this to fail in a debugger. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86694/new/ https://reviews.llvm.org/D86694 Files: clang/lib/Driver/ToolChains/MSVC.cpp compiler-rt/cmake/config-ix.cmake compiler-rt/lib/sanitizer_common/sanitizer_win.cpp compiler-rt/lib/scudo/CMakeLists.txt compiler-rt/lib/scudo/scudo_allocator.cpp compiler-rt/lib/scudo/scudo_crc32.cpp compiler-rt/lib/scudo/scudo_new_delete.cpp compiler-rt/lib/scudo/scudo_platform.h compiler-rt/lib/scudo/scudo_tsd.h compiler-rt/lib/scudo/scudo_tsd_shared.cpp compiler-rt/lib/scudo/scudo_tsd_shared.inc compiler-rt/test/scudo/cxx_threads.cpp compiler-rt/test/scudo/dealloc-race.c compiler-rt/test/scudo/fsanitize.c compiler-rt/test/scudo/interface.cpp compiler-rt/test/scudo/lit.cfg.py compiler-rt/test/scudo/malloc.cpp compiler-rt/test/scudo/memalign.c compiler-rt/test/scudo/mismatch.cpp compiler-rt/test/scudo/overflow.c compiler-rt/test/scudo/preload.cpp compiler-rt/test/scudo/rss.c compiler-rt/test/scudo/secondary.c compiler-rt/test/scudo/symbols.test compiler-rt/test/scudo/threads.c compiler-rt/test/scudo/tsd_destruction.c compiler-rt/test/scudo/valloc.c llvm/CMakeLists.txt llvm/cmake/modules/HandleLLVMOptions.cmake llvm/lib/Support/CMakeLists.txt
Index: llvm/lib/Support/CMakeLists.txt =================================================================== --- llvm/lib/Support/CMakeLists.txt +++ llvm/lib/Support/CMakeLists.txt @@ -58,7 +58,7 @@ string(REGEX REPLACE "(/|\\\\)$" "" LLVM_INTEGRATED_CRT_ALLOC "${LLVM_INTEGRATED_CRT_ALLOC}") if(NOT EXISTS "${LLVM_INTEGRATED_CRT_ALLOC}") - message(FATAL_ERROR "Cannot find the path to `git clone` for the CRT allocator! (${LLVM_INTEGRATED_CRT_ALLOC}). Currently, rpmalloc, snmalloc and mimalloc are supported.") + message(FATAL_ERROR "Cannot find the path to `git clone` for the CRT allocator! (${LLVM_INTEGRATED_CRT_ALLOC}). Currently, rpmalloc, snmalloc, mimalloc and scudo are supported.") endif() if(LLVM_INTEGRATED_CRT_ALLOC MATCHES "rpmalloc$") @@ -73,6 +73,8 @@ message(FATAL_ERROR "Cannot find the mimalloc static library. To build it, first apply the patch from https://github.com/microsoft/mimalloc/issues/268 then build the Release x64 target through ${LLVM_INTEGRATED_CRT_ALLOC}\\ide\\vs2019\\mimalloc.sln") endif() set(system_libs ${system_libs} "${MIMALLOC_LIB}" "-INCLUDE:malloc") + elseif(EXISTS "${LLVM_INTEGRATED_CRT_ALLOC}/clang_rt.scudo-x86_64.lib" AND EXISTS "${LLVM_INTEGRATED_CRT_ALLOC}/clang_rt.scudo_cxx-x86_64.lib") + set(system_libs ${system_libs} "${LLVM_INTEGRATED_CRT_ALLOC}/clang_rt.scudo-x86_64.lib" "${LLVM_INTEGRATED_CRT_ALLOC}/clang_rt.scudo_cxx-x86_64.lib" "-INCLUDE:malloc") endif() endif() Index: llvm/cmake/modules/HandleLLVMOptions.cmake =================================================================== --- llvm/cmake/modules/HandleLLVMOptions.cmake +++ llvm/cmake/modules/HandleLLVMOptions.cmake @@ -790,6 +790,9 @@ elseif (LLVM_USE_SANITIZER STREQUAL "Leaks") append_common_sanitizer_flags() append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + elseif (LLVM_USE_SANITIZER STREQUAL "Scudo") + append_common_sanitizer_flags() + append("-fsanitize=scudo" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) else() message(FATAL_ERROR "Unsupported value of LLVM_USE_SANITIZER: ${LLVM_USE_SANITIZER}") endif() @@ -797,6 +800,9 @@ if (LLVM_USE_SANITIZER STREQUAL "Address") append_common_sanitizer_flags() append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + elseif (LLVM_USE_SANITIZER STREQUAL "Scudo") + append_common_sanitizer_flags() + append("-fsanitize=scudo" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) else() message(FATAL_ERROR "This sanitizer not yet supported in the MSVC environment: ${LLVM_USE_SANITIZER}") endif() Index: llvm/CMakeLists.txt =================================================================== --- llvm/CMakeLists.txt +++ llvm/CMakeLists.txt @@ -528,8 +528,8 @@ if(NOT WIN32) message(FATAL_ERROR "LLVM_INTEGRATED_CRT_ALLOC is only supported on Windows.") endif() - if(LLVM_USE_SANITIZER) - message(FATAL_ERROR "LLVM_INTEGRATED_CRT_ALLOC cannot be used along with LLVM_USE_SANITIZER!") + if(LLVM_USE_SANITIZER AND NOT LLVM_USE_SANITIZER STREQUAL "Scudo") + message(FATAL_ERROR "LLVM_INTEGRATED_CRT_ALLOC cannot be used along with LLVM_USE_SANITIZER (apart from Scudo)!") endif() if(CMAKE_BUILD_TYPE AND uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(FATAL_ERROR "The Debug target isn't supported along with LLVM_INTEGRATED_CRT_ALLOC!") Index: compiler-rt/test/scudo/valloc.c =================================================================== --- compiler-rt/test/scudo/valloc.c +++ compiler-rt/test/scudo/valloc.c @@ -2,7 +2,7 @@ // RUN: %run %t valid 2>&1 // RUN: not %run %t invalid 2>&1 | FileCheck %s // RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t invalid 2>&1 -// UNSUPPORTED: android +// UNSUPPORTED: android, windows // Tests that valloc and pvalloc work as intended. Index: compiler-rt/test/scudo/tsd_destruction.c =================================================================== --- compiler-rt/test/scudo/tsd_destruction.c +++ compiler-rt/test/scudo/tsd_destruction.c @@ -1,5 +1,6 @@ // RUN: %clang_scudo %s -o %t // RUN: %run %t 2>&1 +// UNSUPPORTED: windows #include <locale.h> #include <pthread.h> Index: compiler-rt/test/scudo/threads.c =================================================================== --- compiler-rt/test/scudo/threads.c +++ compiler-rt/test/scudo/threads.c @@ -1,6 +1,7 @@ // RUN: %clang_scudo %s -o %t // RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 // RUN: %env_scudo_opts="QuarantineSizeKb=1024:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 +// UNSUPPORTED: windows // Tests parallel allocations and deallocations of memory chunks from a number // of concurrent threads, with and without quarantine. Index: compiler-rt/test/scudo/symbols.test =================================================================== --- compiler-rt/test/scudo/symbols.test +++ compiler-rt/test/scudo/symbols.test @@ -1,4 +1,4 @@ -UNSUPPORTED: android +UNSUPPORTED: android, windows Verify that various functions are *not* present in the minimal binary. Presence of those symbols in the minimal runtime would mean that the split code made it Index: compiler-rt/test/scudo/secondary.c =================================================================== --- compiler-rt/test/scudo/secondary.c +++ compiler-rt/test/scudo/secondary.c @@ -6,37 +6,60 @@ // allocated by the Secondary allocator, or writing too far in front of it. #include <assert.h> -#include <malloc.h> -#include <signal.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#ifdef _WIN32 +#include <windows.h> +#else +#include <signal.h> #include <unistd.h> +#endif +#ifdef _WIN32 +DWORD getsystempagesize() { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} +LONG WINAPI handler(EXCEPTION_POINTERS *ExceptionInfo) { + fprintf(stderr, "AccessViolation\n"); + ExitProcess(0); +} +#else void handler(int signo, siginfo_t *info, void *uctx) { if (info->si_code == SEGV_ACCERR) { - fprintf(stderr, "SCUDO SIGSEGV\n"); + fprintf(stderr, "AccessViolation\n"); exit(0); } exit(1); } +long getsystempagesize() { + return sysconf(_SC_PAGESIZE); +} +#endif int main(int argc, char **argv) { // The size must be large enough to be serviced by the secondary allocator. - long page_size = sysconf(_SC_PAGESIZE); - size_t size = (1U << 17) + page_size; - struct sigaction a; + long page_size = getsystempagesize(); + size_t size = (1U << 19) + page_size; assert(argc == 2); - memset(&a, 0, sizeof(a)); - a.sa_sigaction = handler; - a.sa_flags = SA_SIGINFO; char *p = (char *)malloc(size); assert(p); memset(p, 'A', size); // This should not trigger anything. // Set up the SIGSEGV handler now, as the rest should trigger an AV. +#ifdef _WIN32 + SetUnhandledExceptionFilter(handler); +#else + struct sigaction a = {0}; + a.sa_sigaction = handler; + a.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &a, NULL); +#endif + if (!strcmp(argv[1], "after")) { for (int i = 0; i < page_size; i++) p[size + i] = 'A'; @@ -50,4 +73,4 @@ return 1; // A successful test means we shouldn't reach this. } -// CHECK: SCUDO SIGSEGV +// CHECK: AccessViolation Index: compiler-rt/test/scudo/rss.c =================================================================== --- compiler-rt/test/scudo/rss.c +++ compiler-rt/test/scudo/rss.c @@ -20,19 +20,31 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#if defined(_WIN32) +#include <windows.h> +#else #include <unistd.h> +#endif static const size_t kNumAllocs = 64; static const size_t kAllocSize = 1 << 20; // 1MB. static void *allocs[kNumAllocs]; +void sleep_ms(unsigned int ms) { +#if defined(_WIN32) + Sleep(ms); +#else + usleep(ms * 1000U); +#endif +} + int main(int argc, char *argv[]) { int returned_null = 0; for (int i = 0; i < kNumAllocs; i++) { // sleep for 100ms every 8 allocations, to allow the RSS check to catch up. if (i != 0 && (i & 0x7) == 0) - usleep(100000); + sleep_ms(100); allocs[i] = malloc(kAllocSize); if (allocs[i]) memset(allocs[i], 0xff, kAllocSize); // Dirty the pages. Index: compiler-rt/test/scudo/preload.cpp =================================================================== --- compiler-rt/test/scudo/preload.cpp +++ compiler-rt/test/scudo/preload.cpp @@ -5,7 +5,7 @@ // RUN: env LD_PRELOAD=%shared_minlibscudo not %run %t 2>&1 | FileCheck %s // This way of setting LD_PRELOAD does not work with Android test runner. -// REQUIRES: !android +// UNSUPPORTED: android, windows #include <assert.h> Index: compiler-rt/test/scudo/overflow.c =================================================================== --- compiler-rt/test/scudo/overflow.c +++ compiler-rt/test/scudo/overflow.c @@ -8,6 +8,11 @@ #include <stdlib.h> #include <string.h> +#if defined(_MSC_VER) +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#endif + int main(int argc, char **argv) { ssize_t offset = sizeof(void *) == 8 ? 8 : 0; Index: compiler-rt/test/scudo/mismatch.cpp =================================================================== --- compiler-rt/test/scudo/mismatch.cpp +++ compiler-rt/test/scudo/mismatch.cpp @@ -28,4 +28,3 @@ } // CHECK-dealloc: ERROR: allocation type mismatch when deallocating address -// CHECK-realloc: ERROR: allocation type mismatch when reallocating address Index: compiler-rt/test/scudo/memalign.c =================================================================== --- compiler-rt/test/scudo/memalign.c +++ compiler-rt/test/scudo/memalign.c @@ -5,6 +5,7 @@ // RUN: not %run %t double-free 2>&1 | FileCheck --check-prefix=CHECK-double-free %s // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t realloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t realloc 2>&1 +// UNSUPPORTED: windows // Tests that the various aligned allocation functions work as intended. Also // tests for the condition where the alignment is not a power of 2. Index: compiler-rt/test/scudo/malloc.cpp =================================================================== --- compiler-rt/test/scudo/malloc.cpp +++ compiler-rt/test/scudo/malloc.cpp @@ -11,6 +11,11 @@ #include <vector> +#if defined(_MSC_VER) +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#endif + int main(int argc, char **argv) { void *p; Index: compiler-rt/test/scudo/lit.cfg.py =================================================================== --- compiler-rt/test/scudo/lit.cfg.py +++ compiler-rt/test/scudo/lit.cfg.py @@ -17,19 +17,22 @@ # C & CXX flags. c_flags = ([config.target_cflags] + - ["-pthread", - "-fPIE", - "-pie", - "-O0", - "-UNDEBUG", - "-ldl", - "-Wl,--gc-sections"]) + ["-O0", + "-UNDEBUG"]) -# Android doesn't want -lrt. -if not config.android: - c_flags += ["-lrt"] +if config.host_os != 'Windows': + c_flags += ["-pthread", + "-fPIE", + "-pie", + "-ldl", + "-Wl,--gc-sections"] + # Android doesn't want -lrt. + if not config.android: + c_flags += ["-lrt"] -cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) +cxx_flags = (c_flags + config.cxx_mode_flags) +if config.host_os != 'Windows': + cxx_flags += ["-std=c++11"] scudo_flags = ["-fsanitize=scudo"] @@ -59,6 +62,6 @@ config.substitutions.append(('%env_scudo_opts=', 'env SCUDO_OPTIONS=' + default_scudo_opts)) -# Hardened Allocator tests are currently supported on Linux only. -if config.host_os not in ['Linux']: +# Hardened Allocator tests are currently supported on Linux and Windows only. +if config.host_os not in ['Linux', 'Windows']: config.unsupported = True Index: compiler-rt/test/scudo/interface.cpp =================================================================== --- compiler-rt/test/scudo/interface.cpp +++ compiler-rt/test/scudo/interface.cpp @@ -10,13 +10,30 @@ #include <stdlib.h> #include <assert.h> #include <string.h> +#if defined(_WIN32) +#include <windows.h> +#else #include <unistd.h> +#endif #include <vector> #include <sanitizer/allocator_interface.h> #include <sanitizer/scudo_interface.h> +#if defined(_MSC_VER) +#include <BaseTsd.h> +typedef SSIZE_T ssize_t; +#endif + +void sleep_ms(unsigned int ms) { +#if defined(_WIN32) + Sleep(ms); +#else + usleep(ms * 1000U); +#endif +} + int main(int argc, char **argv) { assert(argc == 2); @@ -57,7 +74,7 @@ } // Set the soft RSS limit to 1Mb. __scudo_set_rss_limit(1, 0); - usleep(20000); + sleep_ms(200); // The following allocation should return NULL. void *p = malloc(size); assert(!p); @@ -83,7 +100,7 @@ } // Set the hard RSS limit to 1Mb __scudo_set_rss_limit(1, 1); - usleep(20000); + sleep_ms(200); // The following should trigger our death. void *p = malloc(size); } Index: compiler-rt/test/scudo/fsanitize.c =================================================================== --- compiler-rt/test/scudo/fsanitize.c +++ compiler-rt/test/scudo/fsanitize.c @@ -1,5 +1,7 @@ // Test various -fsanitize= additional flags combinations. +// UNSUPPORTED: windows + // RUN: %clang_scudo %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s Index: compiler-rt/test/scudo/dealloc-race.c =================================================================== --- compiler-rt/test/scudo/dealloc-race.c +++ compiler-rt/test/scudo/dealloc-race.c @@ -1,3 +1,5 @@ +// UNSUPPORTED: windows + // RUN: %clang_scudo %s -O2 -o %t // RUN: %env_scudo_opts="QuarantineChunksUpToSize=0" %run %t 2>&1 Index: compiler-rt/test/scudo/cxx_threads.cpp =================================================================== --- /dev/null +++ compiler-rt/test/scudo/cxx_threads.cpp @@ -0,0 +1,73 @@ +// RUN: %clangxx_scudo %s -o %t +// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t 5 1000000 2>&1 +// RUN: %env_scudo_opts="QuarantineSizeKb=1024:ThreadLocalQuarantineSizeKb=64" %run %t 5 1000000 2>&1 + +// Tests parallel allocations and deallocations of memory chunks from a number +// of concurrent threads, with and without quarantine. +// This test passes if everything executes properly without crashing. + +#include <assert.h> +#include <condition_variable> +#include <stdio.h> +#include <stdlib.h> +#include <thread> + +#include <sanitizer/allocator_interface.h> + +int num_threads; +int total_num_alloc; +const int kMaxNumThreads = 500; +std::thread thread[kMaxNumThreads]; + +std::condition_variable cond; +std::mutex mutex; +char go = 0; + +void *thread_fun(void *arg) { + mutex.lock(); + while (!go) { + std::unique_lock<std::mutex> lk(mutex); + cond.wait(lk); + } + + mutex.unlock(); + for (int i = 0; i < total_num_alloc / num_threads; i++) { + void *p = malloc(10); + __asm__ __volatile__("" + : + : "r"(p) + : "memory"); + free(p); + } + return 0; +} + +int main(int argc, char **argv) { + assert(argc == 3); + num_threads = atoi(argv[1]); + assert(num_threads > 0); + assert(num_threads <= kMaxNumThreads); + total_num_alloc = atoi(argv[2]); + assert(total_num_alloc > 0); + + printf("%d threads, %d allocations in each\n", num_threads, + total_num_alloc / num_threads); + fprintf(stderr, "Heap size before: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes before: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + mutex.lock(); + for (int i = 0; i < num_threads; i++) + thread[i] = std::thread(thread_fun, (void *)0); + go = 1; + cond.notify_all(); + mutex.unlock(); + for (int i = 0; i < num_threads; i++) + thread[i].join(); + + fprintf(stderr, "Heap size after: %zd\n", __sanitizer_get_heap_size()); + fprintf(stderr, "Allocated bytes after: %zd\n", + __sanitizer_get_current_allocated_bytes()); + + return 0; +} Index: compiler-rt/lib/scudo/scudo_tsd_shared.inc =================================================================== --- compiler-rt/lib/scudo/scudo_tsd_shared.inc +++ compiler-rt/lib/scudo/scudo_tsd_shared.inc @@ -16,7 +16,11 @@ #if !SCUDO_TSD_EXCLUSIVE +#if SANITIZER_WINDOWS +extern DWORD TlsIndex; +#elif !SANITIZER_ANDROID extern pthread_key_t PThreadKey; +#endif #if SANITIZER_LINUX && !SANITIZER_ANDROID __attribute__((tls_model("initial-exec"))) @@ -24,7 +28,9 @@ #endif ALWAYS_INLINE ScudoTSD* getCurrentTSD() { -#if SANITIZER_ANDROID +#if SANITIZER_WINDOWS + return reinterpret_cast<ScudoTSD *>(TlsGetValue(TlsIndex)); +#elif SANITIZER_ANDROID return reinterpret_cast<ScudoTSD *>(*get_android_tls_ptr()); #elif SANITIZER_LINUX return CurrentTSD; Index: compiler-rt/lib/scudo/scudo_tsd_shared.cpp =================================================================== --- compiler-rt/lib/scudo/scudo_tsd_shared.cpp +++ compiler-rt/lib/scudo/scudo_tsd_shared.cpp @@ -16,8 +16,13 @@ namespace __scudo { +#if !SANITIZER_WINDOWS static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; pthread_key_t PThreadKey; +#else +DWORD TlsIndex = TLS_OUT_OF_INDEXES; +static INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT; +#endif static atomic_uint32_t CurrentIndex; static ScudoTSD *TSDs; @@ -31,7 +36,12 @@ #endif static void initOnce() { +#if SANITIZER_WINDOWS + TlsIndex = TlsAlloc(); + CHECK_NE(TlsIndex, TLS_OUT_OF_INDEXES); +#elif !SANITIZER_ANDROID CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); +#endif initScudo(); NumberOfTSDs = Min(Max(1U, GetNumberOfCPUsCached()), static_cast<u32>(SCUDO_SHARED_TSD_POOL_SIZE)); @@ -48,7 +58,9 @@ } ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { -#if SANITIZER_ANDROID +#if SANITIZER_WINDOWS + CHECK(TlsSetValue(TlsIndex, reinterpret_cast<LPVOID>(TSD))); +#elif SANITIZER_ANDROID *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD); #elif SANITIZER_LINUX CurrentTSD = TSD; @@ -57,8 +69,20 @@ #endif // SANITIZER_ANDROID } +#if SANITIZER_WINDOWS +static BOOL CALLBACK handleInit(PINIT_ONCE InitOnce, PVOID Parameter, + PVOID *Context) { + initOnce(); + return TRUE; +} +#endif + void initThread(bool MinimalInit) { +#if SANITIZER_WINDOWS + CHECK(InitOnceExecuteOnce(&InitOnce, handleInit, nullptr, nullptr)); +#else pthread_once(&GlobalInitialized, initOnce); +#endif // Initial context assignment is done in a plain round-robin fashion. u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); setCurrentTSD(&TSDs[Index % NumberOfTSDs]); Index: compiler-rt/lib/scudo/scudo_tsd.h =================================================================== --- compiler-rt/lib/scudo/scudo_tsd.h +++ compiler-rt/lib/scudo/scudo_tsd.h @@ -18,7 +18,11 @@ #include "scudo_allocator.h" #include "scudo_utils.h" +#if !SANITIZER_WINDOWS #include <pthread.h> +#else +#include <windows.h> +#endif // SANITIZER_WINDOWS namespace __scudo { Index: compiler-rt/lib/scudo/scudo_platform.h =================================================================== --- compiler-rt/lib/scudo/scudo_platform.h +++ compiler-rt/lib/scudo/scudo_platform.h @@ -16,29 +16,26 @@ #include "sanitizer_common/sanitizer_allocator.h" -#if !SANITIZER_LINUX && !SANITIZER_FUCHSIA +#if !SANITIZER_LINUX && !SANITIZER_FUCHSIA && !SANITIZER_WINDOWS # error "The Scudo hardened allocator is not supported on this platform." #endif -#define SCUDO_TSD_EXCLUSIVE_SUPPORTED (!SANITIZER_ANDROID && !SANITIZER_FUCHSIA) +#define SCUDO_TSD_EXCLUSIVE_SUPPORTED \ + (!SANITIZER_ANDROID && !SANITIZER_FUCHSIA && !SANITIZER_WINDOWS) #ifndef SCUDO_TSD_EXCLUSIVE // SCUDO_TSD_EXCLUSIVE wasn't defined, use a default TSD model for the platform. -# if SANITIZER_ANDROID || SANITIZER_FUCHSIA -// Android and Fuchsia use a pool of TSDs shared between threads. -# define SCUDO_TSD_EXCLUSIVE 0 -# elif SANITIZER_LINUX && !SANITIZER_ANDROID -// Non-Android Linux use an exclusive TSD per thread. +#if SCUDO_TSD_EXCLUSIVE_SUPPORTED # define SCUDO_TSD_EXCLUSIVE 1 # else -# error "No default TSD model defined for this platform." -# endif // SANITIZER_ANDROID || SANITIZER_FUCHSIA -#endif // SCUDO_TSD_EXCLUSIVE - +#define SCUDO_TSD_EXCLUSIVE 0 +#endif // SCUDO_TSD_EXCLUSIVE_SUPPORTED +#else // If the exclusive TSD model is chosen, make sure the platform supports it. #if SCUDO_TSD_EXCLUSIVE && !SCUDO_TSD_EXCLUSIVE_SUPPORTED # error "The exclusive TSD model is not supported on this platform." #endif +#endif // SCUDO_TSD_EXCLUSIVE // Maximum number of TSDs that can be created for the Shared model. #ifndef SCUDO_SHARED_TSD_POOL_SIZE @@ -71,6 +68,8 @@ const uptr AllocatorSize = 0x4000000000ULL; // 256G. # elif defined(__aarch64__) const uptr AllocatorSize = 0x10000000000ULL; // 1T. +#elif SANITIZER_WINDOWS +const uptr AllocatorSize = 0x4000000000ULL; // 256G. # else const uptr AllocatorSize = 0x40000000000ULL; // 4T. # endif Index: compiler-rt/lib/scudo/scudo_new_delete.cpp =================================================================== --- compiler-rt/lib/scudo/scudo_new_delete.cpp +++ compiler-rt/lib/scudo/scudo_new_delete.cpp @@ -19,7 +19,32 @@ using namespace __scudo; +// C++ operators can't have dllexport attributes on Windows. We export them +// anyway by passing extra -export flags to the linker, which is exactly that +// dllexport would normally do. We need to export them in order to make the +// VS2015 dynamic CRT (MD) work. +#if SANITIZER_WINDOWS +#define CXX_OPERATOR_ATTRIBUTE +#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym)) +#ifdef _WIN64 +COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new +COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow +COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete +COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete +COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[] +COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[] +#else +COMMENT_EXPORT("??2@YAPAXI@Z") // operator new +COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow +COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete +COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete +COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[] +COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[] +#endif +#undef COMMENT_EXPORT +#else #define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE +#endif // Fake std::nothrow_t to avoid including <new>. namespace std { Index: compiler-rt/lib/scudo/scudo_crc32.cpp =================================================================== --- compiler-rt/lib/scudo/scudo_crc32.cpp +++ compiler-rt/lib/scudo/scudo_crc32.cpp @@ -15,10 +15,13 @@ namespace __scudo { +// Can't override this with weak symbols on Windows +#if !defined(_WIN32) #if defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) u32 computeHardwareCRC32(u32 Crc, uptr Data) { return CRC32_INTRINSIC(Crc, Data); } #endif // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32) +#endif // defined(_WIN32) } // namespace __scudo Index: compiler-rt/lib/scudo/scudo_allocator.cpp =================================================================== --- compiler-rt/lib/scudo/scudo_allocator.cpp +++ compiler-rt/lib/scudo/scudo_allocator.cpp @@ -44,6 +44,12 @@ // at compilation or at runtime. static atomic_uint8_t HashAlgorithm = { CRC32Software }; +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_WEAK_ATTRIBUTE u32 computeHardwareCRC32(u32 Crc, uptr Data) { + return computeSoftwareCRC32(Crc, Data); +} +#endif + inline u32 computeCRC32(u32 Crc, uptr Value, uptr *Array, uptr ArraySize) { // If the hardware CRC32 feature is defined here, it was enabled everywhere, // as opposed to only for scudo_crc32.cpp. This means that other hardware @@ -609,7 +615,7 @@ // last size class minus the header size, in multiples of MinAlignment. UnpackedHeader Header = {}; const uptr MaxPrimaryAlignment = - 1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment); + (uptr)1U << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment); const uptr MaxOffset = (MaxPrimaryAlignment - Chunk::getHeaderSize()) >> MinAlignmentLog; Header.Offset = MaxOffset; Index: compiler-rt/lib/scudo/CMakeLists.txt =================================================================== --- compiler-rt/lib/scudo/CMakeLists.txt +++ compiler-rt/lib/scudo/CMakeLists.txt @@ -4,7 +4,9 @@ set(SCUDO_CFLAGS ${SANITIZER_COMMON_CFLAGS}) # SANITIZER_COMMON_CFLAGS include -fno-builtin, but we actually want builtins! -list(APPEND SCUDO_CFLAGS -fbuiltin) +if (COMPILER_RT_HAS_FBUILTIN_FLAG) + list(APPEND SCUDO_CFLAGS -fbuiltin) +endif() append_rtti_flag(OFF SCUDO_CFLAGS) set(SCUDO_MINIMAL_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) @@ -17,7 +19,9 @@ set(SCUDO_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) # Use gc-sections by default to avoid unused code being pulled in. -list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -Wl,--gc-sections) +if (!WIN32) + list(APPEND SCUDO_DYNAMIC_LINK_FLAGS -Wl,--gc-sections) +endif() if(ANDROID) # Put most Sanitizer shared libraries in the global group. For more details, see Index: compiler-rt/lib/sanitizer_common/sanitizer_win.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -21,6 +21,13 @@ #include <psapi.h> #include <stdlib.h> +// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the +// "Community Additions" comment on MSDN here: +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +#define SystemFunction036 NTAPI SystemFunction036 +#include <NTSecAPI.h> +#undef SystemFunction036 + #include "sanitizer_common.h" #include "sanitizer_file.h" #include "sanitizer_libc.h" @@ -1106,9 +1113,11 @@ // Do nothing. } -// FIXME: implement on this platform. +#pragma comment(lib, "advapi32.lib") bool GetRandom(void *buffer, uptr length, bool blocking) { - UNIMPLEMENTED(); + if (!buffer || !length || length > 256) + return false; + return RtlGenRandom(buffer, length) != FALSE; } u32 GetNumberOfCPUs() { Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -58,6 +58,7 @@ check_c_compiler_flag(-std=c11 COMPILER_RT_HAS_STD_C11_FLAG) check_cxx_compiler_flag(-fPIC COMPILER_RT_HAS_FPIC_FLAG) check_cxx_compiler_flag(-fPIE COMPILER_RT_HAS_FPIE_FLAG) +check_cxx_compiler_flag(-fbuiltin COMPILER_RT_HAS_FBUILTIN_FLAG) check_cxx_compiler_flag(-fno-builtin COMPILER_RT_HAS_FNO_BUILTIN_FLAG) check_cxx_compiler_flag(-fno-exceptions COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG) check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG) @@ -764,7 +765,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|Android|Fuchsia") + OS_NAME MATCHES "Linux|Android|Fuchsia|Windows") set(COMPILER_RT_HAS_SCUDO TRUE) else() set(COMPILER_RT_HAS_SCUDO FALSE) Index: clang/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- clang/lib/Driver/ToolChains/MSVC.cpp +++ clang/lib/Driver/ToolChains/MSVC.cpp @@ -447,6 +447,13 @@ } } + if (TC.getSanitizerArgs().needsScudoRt()) { + for (const auto &Lib : {"scudo", "scudo_cxx"}) { + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); + } + CmdArgs.push_back(Args.MakeArgString("-include:malloc")); + } + Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Control Flow Guard checks @@ -1404,6 +1411,7 @@ Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Scudo; Res &= ~SanitizerKind::CFIMFCall; return Res; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits