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
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to