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|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" @@ -763,7 +770,10 @@ } uptr GetRSS() { - return 0; + PROCESS_MEMORY_COUNTERS counters; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + return 0; + return counters.WorkingSetSize; } void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } @@ -1108,9 +1118,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 @@ -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; @@ -334,6 +340,7 @@ // RSS from /proc/self/statm by default. We might want to // call getrusage directly, even if it's less accurate. const uptr CurrentRssMb = GetRSS() >> 20; + Printf("CurrentRssMb = %d\n", CurrentRssMb); if (HardRssLimitMb && HardRssLimitMb < CurrentRssMb) { Report("%s: hard RSS limit exhausted (%zdMb vs %zdMb)\n", SanitizerToolName, HardRssLimitMb, CurrentRssMb); Index: lib/scudo/scudo_allocator_secondary.h =================================================================== --- lib/scudo/scudo_allocator_secondary.h +++ lib/scudo/scudo_allocator_secondary.h @@ -62,14 +62,14 @@ const uptr NewMapBeg = RoundDownTo(UserBeg - HeadersSize, PageSize) - PageSize; DCHECK_GE(NewMapBeg, MapBeg); - if (NewMapBeg != MapBeg) { + if (!SANITIZER_WINDOWS && NewMapBeg != MapBeg) { AddressRange.Unmap(MapBeg, NewMapBeg - MapBeg); MapBeg = NewMapBeg; } UserEnd = UserBeg + UserSize; } const uptr NewMapEnd = RoundUpTo(UserEnd, PageSize) + PageSize; - if (NewMapEnd != MapEnd) { + if (!SANITIZER_WINDOWS && NewMapEnd != MapEnd) { AddressRange.Unmap(NewMapEnd, MapEnd - NewMapEnd); MapEnd = NewMapEnd; } 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/double-free.cpp =================================================================== --- test/scudo/double-free.cpp +++ test/scudo/double-free.cpp @@ -2,7 +2,6 @@ // RUN: not %run %t malloc 2>&1 | FileCheck %s // RUN: not %run %t new 2>&1 | FileCheck %s // RUN: not %run %t newarray 2>&1 | FileCheck %s -// RUN: not %run %t memalign 2>&1 | FileCheck %s // Tests double-free error on pointers allocated with different allocation // functions. @@ -32,13 +31,6 @@ delete[] p; delete[] p; } - if (!strcmp(argv[1], "memalign")) { - void *p = nullptr; - posix_memalign(&p, 0x100, sizeof(int)); - assert(p); - free(p); - free(p); - } return 0; } 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/mismatch.cpp =================================================================== --- test/scudo/mismatch.cpp +++ test/scudo/mismatch.cpp @@ -3,16 +3,11 @@ // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t mallocdel 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t newfree 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t newfree 2>&1 -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memaligndel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t memaligndel 2>&1 -// RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t memalignrealloc 2>&1 | FileCheck --check-prefix=CHECK-realloc %s -// RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t memalignrealloc 2>&1 // Tests that type mismatches between allocation and deallocation functions are // caught when the related option is set. #include -#include #include #include @@ -29,19 +24,7 @@ assert(p); free((void *)p); } - if (!strcmp(argv[1], "memaligndel")) { - int *p = (int *)memalign(16, 16); - assert(p); - delete p; - } - if (!strcmp(argv[1], "memalignrealloc")) { - void *p = memalign(16, 16); - assert(p); - p = realloc(p, 32); - free(p); - } return 0; } // 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/realloc.cpp =================================================================== --- test/scudo/realloc.cpp +++ test/scudo/realloc.cpp @@ -15,6 +15,8 @@ #include +#include + int main(int argc, char **argv) { void *p, *old_p; @@ -35,7 +37,7 @@ if (p) free(p); size += 16; p = malloc(size); - usable_size = malloc_usable_size(p); + usable_size = __sanitizer_get_allocated_size(p); assert(usable_size >= size); } while (usable_size == size); for (int i = 0; i < usable_size; i++) @@ -56,7 +58,7 @@ if (!strcmp(argv[1], "pointers")) { old_p = p = realloc(nullptr, size); assert(p); - size = malloc_usable_size(p); + size = __sanitizer_get_allocated_size(p); // Our realloc implementation will return the same pointer if the size // requested is lower than or equal to the usable size of the associated // chunk. 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/sizes.cpp =================================================================== --- test/scudo/sizes.cpp +++ test/scudo/sizes.cpp @@ -21,10 +21,10 @@ #include #include +#include + int main(int argc, char **argv) { assert(argc == 2); - const char *action = argv[1]; - fprintf(stderr, "%s:\n", action); #if __LP64__ || defined(_WIN64) static const size_t kMaxAllowedMallocSize = 1ULL << 40; @@ -34,32 +34,32 @@ static const size_t kChunkHeaderSize = 8; #endif - if (!strcmp(action, "malloc")) { + if (!strcmp(argv[1], "malloc")) { void *p = malloc(kMaxAllowedMallocSize); assert(!p); p = malloc(kMaxAllowedMallocSize - kChunkHeaderSize); assert(!p); - } else if (!strcmp(action, "calloc")) { + } else if (!strcmp(argv[1], "calloc")) { // Trigger an overflow in calloc. size_t size = std::numeric_limits::max(); void *p = calloc((size / 0x1000) + 1, 0x1000); assert(!p); - } else if (!strcmp(action, "new")) { + } else if (!strcmp(argv[1], "new")) { void *p = operator new(kMaxAllowedMallocSize); assert(!p); - } else if (!strcmp(action, "new-nothrow")) { + } else if (!strcmp(argv[1], "new-nothrow")) { void *p = operator new(kMaxAllowedMallocSize, std::nothrow); assert(!p); - } else if (!strcmp(action, "usable")) { + } else if (!strcmp(argv[1], "usable")) { // Playing with the actual usable size of a chunk. void *p = malloc(1007); assert(p); - size_t size = malloc_usable_size(p); + size_t size = __sanitizer_get_allocated_size(p); assert(size >= 1007); memset(p, 'A', size); p = realloc(p, 2014); assert(p); - size = malloc_usable_size(p); + size = __sanitizer_get_allocated_size(p); assert(size >= 2014); memset(p, 'B', size); free(p);