russell.gallop updated this revision to Diff 291235.
russell.gallop edited the summary of this revision.
russell.gallop added a comment.
Herald added subscribers: phosek, hiraditya.
Fixup scudo (sanitizer based) to work on Windows.
This makes use of the CRT alloc hooks from D71786
<https://reviews.llvm.org/D71786>.
To build with scudo on Windows use:
-DLLVM_INTEGRATED_CRT_ALLOC=<llvm-project>/stage1/lib/clang/12.0.0/lib/windows/clang_rt.scudo-x86_64.lib
-DLLVM_USE_CRT_RELEASE=MT
-DLLVM_USE_SANITIZER=Scudo is supported in this patch, but isn't required.
@cryptoad on Linux does this do anything other than add libraries when using
clang to drive the linker?
Limitations:
-Note that this is not using hardware CRC32.
-This just hooks in the C scudo library, not the cxx library
I evaluated this on a 3 stage LLVM build on Windows 10 2004 (in vs2019 16.7.3
environment) on a 6-core i7-8700k.
- stage1 builds the scudo sanitizer on Windows: requires
-DLLVM_ENABLE_PROJECTS=clang;lld;compiler-rt
- stage2: built with -DCMAKE_C_COMPILER="<stage1>/bin/clang-cl.exe"
-DCMAKE_CXX_COMPILER="<stage1>/bin/clang-cl.exe"
-DCMAKE_LINKER="<stage1>/bin/lld-link.exe" -DLLVM_USE_CRT_RELEASE=MT
-DCMAKE_BUILD_TYPE=Release
- stage2_scudo: as stage2 plus
-DLLVM_INTEGRATED_CRT_ALLOC=<stage1>/lib/clang/12.0.0/lib/windows/clang_rt.scudo-x86_64.lib
Then evaluated linking clang with ThinLTO:
- stage3: -DCMAKE_C_COMPILER="<stage2>/bin/clang-cl.exe"
-DCMAKE_CXX_COMPILER="<stage2>/bin/clang-cl.exe"
-DCMAKE_LINKER="<stage2>/bin/lld-link.exe" -DLLVM_USE_CRT_RELEASE=MT
-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_LTO=Thin
- stage3_scudo: -DCMAKE_C_COMPILER="<stage2_scudo>/bin/clang-cl.exe"
-DCMAKE_CXX_COMPILER="<stage2_scudo>/bin/clang-cl.exe"
-DCMAKE_LINKER="<stage2_scudo>/bin/lld-link.exe" -DLLVM_USE_CRT_RELEASE=MT
-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_LTO=Thin
I set /threads:12 and removed /lldltocache.
Without SCUDO_OPTIONS scudo seems to be about 25% slower.
>"hyperfine.exe" -m 3 -w 1 "cd stage3\repro &&
f:\git\llvm-project\stage2\bin\lld-link @response.txt" "cd stage3_scudo\repro
&& f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt"
Benchmark #1: cd stage3\repro && f:\git\llvm-project\stage2\bin\lld-link
@response.txt
Time (mean ± σ): 268.209 s ± 4.966 s [User: 18.1 ms, System: 6.6 ms]
Range (min … max): 263.223 s … 273.155 s 3 runs
Benchmark #2: cd stage3_scudo\repro &&
f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt
Time (mean ± σ): 334.312 s ± 4.002 s [User: 2.4 ms, System: 14.6 ms]
Range (min … max): 329.889 s … 337.683 s 3 runs
Summary
'cd stage3\repro && f:\git\llvm-project\stage2\bin\lld-link @response.txt'
ran
1.25 ± 0.03 times faster than 'cd stage3_scudo\repro &&
f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt'
I set scudo options to disable quarantine and mismatch checking and it seems to
be about 8% slower.
>set
SCUDO_OPTIONS=allocator_release_to_os_interval_ms=-1:QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0:DeleteSizeMismatch=0:DeallocationTypeMismatch=0
>"hyperfine.exe" -m 3 -w 1 "cd stage3\repro &&
f:\git\llvm-project\stage2\bin\lld-link @response.txt" "cd stage3_scudo\repro
&& f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt"
Benchmark #1: cd stage3\repro && f:\git\llvm-project\stage2\bin\lld-link
@response.txt
Time (mean ± σ): 273.772 s ± 3.624 s [User: 1.3 ms, System: 8.6 ms]
Range (min … max): 269.806 s … 276.909 s 3 runs
Benchmark #2: cd stage3_scudo\repro &&
f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt
Time (mean ± σ): 296.593 s ± 2.362 s [User: 1.3 ms, System: 13.9 ms]
Range (min … max): 293.917 s … 298.391 s 3 runs
Summary
'cd stage3\repro && f:\git\llvm-project\stage2\bin\lld-link @response.txt'
ran
1.08 ± 0.02 times faster than 'cd stage3_scudo\repro &&
f:\git\llvm-project\stage2_scudo\bin\lld-link @response.txt'
It's worth noting that the run without scudo was not using all CPU so still
hitting some locking issues but was still over 90%. With both scudo runs it was
pegged at 100% CPU until near the end of the link. From this it appears that
the locking behaviour is better than the default allocator and would win out on
a wide enough processor. The loss in straight line performance is potentially
due to CRC calculations (not using hardware).
@cryptoad are those the best scudo flags to evaluate for performance?
I'm looking at porting scudo standalone to Windows.
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/sanitizer_common/CMakeLists.txt
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/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
@@ -73,7 +73,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$")
@@ -89,6 +89,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(LLVM_INTEGRATED_CRT_ALLOC MATCHES "scudo")
+ set(system_libs ${system_libs} "${LLVM_INTEGRATED_CRT_ALLOC}" "-INCLUDE:malloc")
endif()
endif()
Index: llvm/cmake/modules/HandleLLVMOptions.cmake
===================================================================
--- llvm/cmake/modules/HandleLLVMOptions.cmake
+++ llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -789,6 +789,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()
@@ -796,6 +799,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
@@ -572,8 +572,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, win32
// 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: win32
#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: win32
// Tests parallel allocations and deallocations of memory chunks from a number
// of concurrent threads, with and without quarantine.
Index: compiler-rt/test/scudo/secondary.c
===================================================================
--- compiler-rt/test/scudo/secondary.c
+++ compiler-rt/test/scudo/secondary.c
@@ -6,37 +6,59 @@
// 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 getpagesize() {
+ 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 getpagesize() {
+ 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 = getpagesize();
+ size_t size = (1U << 19) + page_size;
assert(argc == 2);
- memset(&a, 0, sizeof(a));
+
+#ifdef _WIN32
+ SetUnhandledExceptionFilter(handler);
+#else
+ struct sigaction a = {0};
a.sa_sigaction = handler;
a.sa_flags = SA_SIGINFO;
+ sigaction(SIGSEGV, &a, NULL);
+#endif
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.
- sigaction(SIGSEGV, &a, NULL);
+ memset(p, 'A', size);
if (!strcmp(argv[1], "after")) {
for (int i = 0; i < page_size; i++)
p[size + i] = 'A';
@@ -50,4 +72,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, win32
#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: win32
// 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,23 @@
# C & CXX flags.
c_flags = ([config.target_cflags] +
- ["-pthread",
- "-fPIE",
- "-pie",
- "-O0",
- "-UNDEBUG",
- "-ldl",
- "-Wl,--gc-sections"])
+c_flags = ([config.target_cflags] +
+ ["-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 +63,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/sanitizer_common/CMakeLists.txt
===================================================================
--- compiler-rt/test/sanitizer_common/CMakeLists.txt
+++ compiler-rt/test/sanitizer_common/CMakeLists.txt
@@ -11,7 +11,7 @@
# FIXME(dliew): We should switch to COMPILER_RT_SANITIZERS_TO_BUILD instead of
# the hard coded `SUPPORTED_TOOLS_INIT` list once we know that the other
# sanitizers work.
-set(SUPPORTED_TOOLS_INIT asan lsan msan tsan ubsan)
+set(SUPPORTED_TOOLS_INIT asan lsan msan tsan ubsan scudo)
set(SUPPORTED_TOOLS)
foreach(SANITIZER_TOOL ${SUPPORTED_TOOLS_INIT})
string(TOUPPER ${SANITIZER_TOOL} SANITIZER_TOOL_UPPER)
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
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);
+ 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
@@ -17,7 +17,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"
@@ -1103,9 +1110,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
@@ -743,7 +743,7 @@
endif()
#TODO(kostyak): add back Android & Fuchsia when the code settles a bit.
-if (SCUDO_STANDALONE_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux" AND
+if (SCUDO_STANDALONE_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux|Windows" AND
COMPILER_RT_HAS_AUXV)
set(COMPILER_RT_HAS_SCUDO_STANDALONE TRUE)
else()
@@ -751,7 +751,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
@@ -1402,6 +1402,7 @@
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
+ Res |= SanitizerKind::Scudo;
Res &= ~SanitizerKind::CFIMFCall;
return Res;
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits