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
  • [PATCH] D86694: [scudo] Al... Russell Gallop via Phabricator via cfe-commits

Reply via email to