russell.gallop created this revision.
russell.gallop added reviewers: cryptoad, aganea.
Herald added subscribers: phosek, mgorny.
russell.gallop requested review of this revision.
Herald added projects: clang, Sanitizers.
Herald added subscribers: Sanitizers, cfe-commits.

Based on https://reviews.llvm.org/D42519, this ports the sanitizer version of 
scudo to Windows.

Passes lit tests and when used as the allocator for LLVM, that passes 
check-all. Have noticed that on LLVM with Scudo, 
https://bugs.llvm.org/show_bug.cgi?id=24978 does intermittently occur when 
running lli tests.

For more details of evaluation see https://reviews.llvm.org/D86694

A separate review will allow hooking this in as the memory allocator for LLVM.

I'm aware that scudo sanitizer version is not under active development. This is 
intended as a step to porting scudo standalone.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D96120

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

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
@@ -608,8 +614,8 @@
   // result, the maximum offset will be at most the maximum alignment for the
   // last size class minus the header size, in multiples of MinAlignment.
   UnpackedHeader Header = {};
-  const uptr MaxPrimaryAlignment =
-      1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment);
+  const uptr MaxPrimaryAlignment = (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 (COMPILER_RT_HAS_GC_SECTIONS)
+  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"
@@ -1113,9 +1120,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)
@@ -177,6 +178,8 @@
   check_library_exists(log __android_log_write "" COMPILER_RT_HAS_LIBLOG)
 endif()
 
+check_linker_flag("-Wl,--gc-sections" COMPILER_RT_HAS_GC_SECTIONS)
+
 # Architectures.
 
 # List of all architectures we can target.
@@ -765,7 +768,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
@@ -486,6 +486,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
@@ -1344,6 +1351,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