Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -590,7 +590,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SCUDO_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|Android") + OS_NAME MATCHES "Linux|Android|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 @@ -21,6 +21,7 @@ #include #include #include +#include #include "sanitizer_common.h" #include "sanitizer_dbghelp.h" @@ -1101,14 +1102,23 @@ // Do nothing. } -// FIXME: implement on this platform. bool GetRandom(void *buffer, uptr length, bool blocking) { - UNIMPLEMENTED(); + if (!buffer || !length || length > 256) + return false; + HCRYPTPROV provider = 0; + if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return false; + auto at_scope_exit([&] { CryptReleaseContext(provider, 0); }); + if (!CryptGenRandom(provider, length, reinterpret_cast(buffer))) + return false; + return true; } -// FIXME: implement on this platform. u32 GetNumberOfCPUs() { - UNIMPLEMENTED(); + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; } } // namespace __sanitizer 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 @@ -249,7 +255,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 - AlignedChunkHeaderSize) >> MinAlignmentLog; Header.Offset = MaxOffset; @@ -736,6 +742,12 @@ return Instance.getUsableSize(Ptr); } +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, + void *ptr, uptr size) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {} +#endif + // Interface functions void __scudo_set_rss_limit(uptr LimitMb, s32 HardLimit) { Index: lib/scudo/scudo_flags.cpp =================================================================== --- lib/scudo/scudo_flags.cpp +++ lib/scudo/scudo_flags.cpp @@ -12,13 +12,12 @@ //===----------------------------------------------------------------------===// #include "scudo_flags.h" +#include "scudo_interface_internal.h" #include "scudo_utils.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" -SANITIZER_INTERFACE_WEAK_DEF(const char*, __scudo_default_options, void); - namespace __scudo { static Flags ScudoFlags; // Use via getFlags(). @@ -119,3 +118,9 @@ } } // namespace __scudo + +#if !SANITIZER_SUPPORTS_WEAK_HOOKS +SANITIZER_INTERFACE_WEAK_DEF(const char*, __scudo_default_options, void) { + return ""; +} +#endif Index: lib/scudo/scudo_interceptors.cpp =================================================================== --- lib/scudo/scudo_interceptors.cpp +++ lib/scudo/scudo_interceptors.cpp @@ -17,54 +17,68 @@ using namespace __scudo; -INTERCEPTOR(void, free, void *ptr) { - scudoFree(ptr, FromMalloc); -} +extern "C" { -INTERCEPTOR(void, cfree, void *ptr) { +INTERCEPTOR_ATTRIBUTE void free(void *ptr) { scudoFree(ptr, FromMalloc); } -INTERCEPTOR(void*, malloc, uptr size) { +INTERCEPTOR_ATTRIBUTE void *malloc(size_t size) { return scudoMalloc(size, FromMalloc); } -INTERCEPTOR(void*, realloc, void *ptr, uptr size) { +INTERCEPTOR_ATTRIBUTE void *realloc(void *ptr, size_t size) { return scudoRealloc(ptr, size); } -INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { +INTERCEPTOR_ATTRIBUTE void *calloc(size_t nmemb, size_t size) { return scudoCalloc(nmemb, size); } -INTERCEPTOR(void*, valloc, uptr size) { +INTERCEPTOR_ATTRIBUTE void *valloc(size_t size) { return scudoValloc(size); } -INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { - return scudoMemalign(alignment, size); +INTERCEPTOR_ATTRIBUTE +int posix_memalign(void **memptr, size_t alignment, size_t size) { + return scudoPosixMemalign(memptr, alignment, size); } -INTERCEPTOR(void*, __libc_memalign, uptr alignment, uptr size) { +#if SANITIZER_INTERCEPT_CFREE +INTERCEPTOR_ATTRIBUTE void cfree(void *ptr) ALIAS("free"); +#endif + +#if SANITIZER_INTERCEPT_MEMALIGN +INTERCEPTOR_ATTRIBUTE void *memalign(size_t alignment, size_t size) { return scudoMemalign(alignment, size); } -INTERCEPTOR(void*, pvalloc, uptr size) { +INTERCEPTOR_ATTRIBUTE +void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign"); +#endif + +#if SANITIZER_INTERCEPT_PVALLOC +INTERCEPTOR_ATTRIBUTE void *pvalloc(size_t size) { return scudoPvalloc(size); } +#endif -INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC +INTERCEPTOR_ATTRIBUTE void *aligned_alloc(size_t alignment, size_t size) { return scudoAlignedAlloc(alignment, size); } +#endif -INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { - return scudoPosixMemalign(memptr, alignment, size); -} - -INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { +#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE +INTERCEPTOR_ATTRIBUTE size_t malloc_usable_size(void *ptr) { return scudoMallocUsableSize(ptr); } +#endif -INTERCEPTOR(int, mallopt, int cmd, int value) { +#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO +INTERCEPTOR_ATTRIBUTE int mallopt(int cmd, int value) { return -1; } +#endif + +} // extern "C" Index: lib/scudo/scudo_interface_internal.h =================================================================== --- lib/scudo/scudo_interface_internal.h +++ lib/scudo/scudo_interface_internal.h @@ -20,6 +20,8 @@ using __sanitizer::s32; extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +const char *__scudo_default_options(); SANITIZER_INTERFACE_ATTRIBUTE void __scudo_set_rss_limit(uptr LimitMb, s32 HardLimit); } // extern "C" 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/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"]) + ["-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"] @@ -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