Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -593,7 +593,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: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -22,6 +22,13 @@ #include #include +// #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 +#undef SystemFunction036 + #include "sanitizer_common.h" #include "sanitizer_dbghelp.h" #include "sanitizer_file.h" @@ -1112,9 +1119,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: lib/scudo/scudo_allocator.cpp =================================================================== --- lib/scudo/scudo_allocator.cpp +++ lib/scudo/scudo_allocator.cpp @@ -37,6 +37,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 @@ -243,7 +249,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: lib/scudo/scudo_new_delete.cpp =================================================================== --- lib/scudo/scudo_new_delete.cpp +++ 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 . namespace std { Index: lib/scudo/scudo_platform.h =================================================================== --- lib/scudo/scudo_platform.h +++ lib/scudo/scudo_platform.h @@ -17,29 +17,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 +# if SCUDO_TSD_EXCLUSIVE && !SCUDO_TSD_EXCLUSIVE_SUPPORTED # error "The exclusive TSD model is not supported on this platform." -#endif +# endif +#endif // SCUDO_TSD_EXCLUSIVE // Maximum number of TSDs that can be created for the Shared model. #ifndef SCUDO_SHARED_TSD_POOL_SIZE Index: lib/scudo/scudo_tsd.h =================================================================== --- lib/scudo/scudo_tsd.h +++ lib/scudo/scudo_tsd.h @@ -19,7 +19,11 @@ #include "scudo_allocator.h" #include "scudo_utils.h" -#include +#if !SANITIZER_WINDOWS +# include +#else +# include +#endif // SANITIZER_WINDOWS namespace __scudo { Index: lib/scudo/scudo_tsd_shared.cpp =================================================================== --- lib/scudo/scudo_tsd_shared.cpp +++ lib/scudo/scudo_tsd_shared.cpp @@ -17,15 +17,25 @@ 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; static u32 NumberOfTSDs; 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(SCUDO_SHARED_TSD_POOL_SIZE)); @@ -36,15 +46,29 @@ } ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { -#if SANITIZER_ANDROID +#if SANITIZER_WINDOWS + CHECK(TlsSetValue(TlsIndex, reinterpret_cast(TSD))); +#elif SANITIZER_ANDROID *get_android_tls_ptr() = reinterpret_cast(TSD); #else CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast(TSD)), 0); #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: lib/scudo/scudo_tsd_shared.inc =================================================================== --- lib/scudo/scudo_tsd_shared.inc +++ lib/scudo/scudo_tsd_shared.inc @@ -17,10 +17,16 @@ #if !SCUDO_TSD_EXCLUSIVE +#if SANITIZER_WINDOWS +extern DWORD TlsIndex; +#elif !SANITIZER_ANDROID extern pthread_key_t PThreadKey; +#endif ALWAYS_INLINE ScudoTSD* getCurrentTSD() { -#if SANITIZER_ANDROID +#if SANITIZER_WINDOWS + return reinterpret_cast(TlsGetValue(TlsIndex)); +#elif SANITIZER_ANDROID return reinterpret_cast(*get_android_tls_ptr()); #else return reinterpret_cast(pthread_getspecific(PThreadKey)); Index: test/scudo/interface.cpp =================================================================== --- test/scudo/interface.cpp +++ test/scudo/interface.cpp @@ -10,13 +10,30 @@ #include #include #include -#include +#if defined(_WIN32) +# include +#else +# include +#endif #include #include #include +#if defined(_MSC_VER) +#include +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: test/scudo/lit.cfg =================================================================== --- test/scudo/lit.cfg +++ test/scudo/lit.cfg @@ -16,19 +16,22 @@ # C & CXX flags. c_flags = ([config.target_cflags] + - ["-pthread", - "-fPIE", - "-pie", - "-O0", - "-UNDEBUG", - "-ldl", - "-Wl,--gc-sections"]) - -# Android doesn't want -lrt. -if not config.android: - c_flags += ["-lrt"] + ["-O0", + "-UNDEBUG"]) -cxx_flags = (c_flags + config.cxx_mode_flags + ["-std=c++11"]) +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) +if config.host_os != 'Windows': + cxx_flags += ["-std=c++11"] scudo_flags = ["-fsanitize=scudo"] @@ -54,5 +57,5 @@ 'env SCUDO_OPTIONS=' + default_scudo_opts)) # Hardened Allocator tests are currently supported on Linux only. -if config.host_os not in ['Linux']: +if config.host_os not in ['Linux', 'Windows']: config.unsupported = True Index: test/scudo/malloc.cpp =================================================================== --- test/scudo/malloc.cpp +++ test/scudo/malloc.cpp @@ -11,6 +11,11 @@ #include +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + int main(int argc, char **argv) { void *p; Index: test/scudo/memalign.c =================================================================== --- test/scudo/memalign.c +++ 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: test/scudo/mismatch.cpp =================================================================== --- test/scudo/mismatch.cpp +++ 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: test/scudo/overflow.c =================================================================== --- test/scudo/overflow.c +++ test/scudo/overflow.c @@ -8,6 +8,11 @@ #include #include +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + int main(int argc, char **argv) { ssize_t offset = sizeof(void *) == 8 ? 8 : 0; Index: test/scudo/preload.cpp =================================================================== --- test/scudo/preload.cpp +++ test/scudo/preload.cpp @@ -4,7 +4,7 @@ // RUN: env LD_PRELOAD=%shared_libscudo 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 Index: test/scudo/rss.c =================================================================== --- test/scudo/rss.c +++ test/scudo/rss.c @@ -20,18 +20,30 @@ #include #include #include -#include +#if defined(_WIN32) +# include +#else +# include +#endif static const size_t kNumAllocs = 128; 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++) { if ((i & 0xf) == 0) - usleep(50000); + sleep_ms(50); allocs[i] = malloc(kAllocSize); if (allocs[i]) memset(allocs[i], 0xff, kAllocSize); // Dirty the pages. Index: test/scudo/secondary.c =================================================================== --- test/scudo/secondary.c +++ test/scudo/secondary.c @@ -6,37 +6,60 @@ // allocated by the Secondary allocator, or writing too far in front of it. #include -#include -#include #include #include -#include - +#include +#ifdef _WIN32 +# include +#else +# include +# include +#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 +73,4 @@ return 1; // A successful test means we shouldn't reach this. } -// CHECK: SCUDO SIGSEGV +// CHECK: AccessViolation Index: test/scudo/threads.c =================================================================== --- test/scudo/threads.c +++ 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: test/scudo/tsd_destruction.c =================================================================== --- test/scudo/tsd_destruction.c +++ test/scudo/tsd_destruction.c @@ -1,5 +1,6 @@ // RUN: %clang_scudo %s -o %t // RUN: %run %t 2>&1 +// UNSUPPORTED: win32 #include #include Index: test/scudo/valloc.c =================================================================== --- test/scudo/valloc.c +++ test/scudo/valloc.c @@ -2,7 +2,7 @@ // RUN: %run %t valid 2>&1 // RUN: not %run %t invalid 2>&1 // 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.