Index: lib/scudo/CMakeLists.txt =================================================================== --- lib/scudo/CMakeLists.txt +++ lib/scudo/CMakeLists.txt @@ -12,12 +12,14 @@ scudo_flags.cpp scudo_crc32.cpp scudo_interceptors.cpp - scudo_new_delete.cpp scudo_termination.cpp scudo_tsd_exclusive.cpp scudo_tsd_shared.cpp scudo_utils.cpp) +set(SCUDO_CXX_SOURCES + scudo_new_delete.cpp) + # Enable the SSE 4.2 instruction set for scudo_crc32.cpp, if available. if (COMPILER_RT_HAS_MSSE4_2_FLAG) set_source_files_properties(scudo_crc32.cpp PROPERTIES COMPILE_FLAGS -msse4.2) @@ -36,26 +38,33 @@ append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread SCUDO_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBLOG log SCUDO_DYNAMIC_LIBS) - foreach(arch ${SCUDO_SUPPORTED_ARCH}) - add_compiler_rt_runtime(clang_rt.scudo - STATIC - ARCHS ${arch} - SOURCES ${SCUDO_SOURCES} - OBJECT_LIBS RTSanitizerCommonNoTermination - RTSanitizerCommonLibc - RTInterception - CFLAGS ${SCUDO_CFLAGS} - PARENT_TARGET scudo) - - add_compiler_rt_runtime(clang_rt.scudo - SHARED - ARCHS ${arch} - SOURCES ${SCUDO_SOURCES} - OBJECT_LIBS RTSanitizerCommonNoTermination - RTSanitizerCommonLibc - RTInterception - CFLAGS ${SCUDO_CFLAGS} - LINK_LIBS ${SCUDO_DYNAMIC_LIBS} - PARENT_TARGET scudo) - endforeach() + add_compiler_rt_runtime(clang_rt.scudo + STATIC + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_SOURCES} + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception + RTUbsan + CFLAGS ${SCUDO_CFLAGS} + PARENT_TARGET scudo) + + add_compiler_rt_runtime(clang_rt.scudo_cxx + STATIC + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_CXX_SOURCES} + OBJECT_LIBS RTUbsan_cxx + CFLAGS ${SCUDO_CFLAGS} + PARENT_TARGET scudo) + + add_compiler_rt_runtime(clang_rt.scudo + SHARED + ARCHS ${SCUDO_SUPPORTED_ARCH} + SOURCES ${SCUDO_SOURCES} ${SCUDO_CXX_SOURCES} + OBJECT_LIBS RTSanitizerCommonNoTermination + RTSanitizerCommonLibc + RTInterception + CFLAGS ${SCUDO_CFLAGS} + LINK_LIBS ${SCUDO_DYNAMIC_LIBS} + PARENT_TARGET scudo) endif() Index: test/scudo/alignment.c =================================================================== --- test/scudo/alignment.c +++ test/scudo/alignment.c @@ -15,7 +15,7 @@ if (!strcmp(argv[1], "pointers")) { void *p = malloc(1U << 16); assert(p); - free(reinterpret_cast(reinterpret_cast(p) | 1)); + free((void *)((uintptr_t)p | 1)); } return 0; } Index: test/scudo/alignment.cpp =================================================================== --- test/scudo/alignment.cpp +++ test/scudo/alignment.cpp @@ -1,23 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: not %run %t pointers 2>&1 | FileCheck %s - -// Tests that a non MinAlignment aligned pointer will trigger the associated -// error on deallocation. - -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - assert(argc == 2); - if (!strcmp(argv[1], "pointers")) { - void *p = malloc(1U << 16); - assert(p); - free(reinterpret_cast(reinterpret_cast(p) | 1)); - } - return 0; -} - -// CHECK: ERROR: attempted to deallocate a chunk not properly aligned Index: test/scudo/double-free.cpp =================================================================== --- test/scudo/double-free.cpp +++ test/scudo/double-free.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // 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 Index: test/scudo/interface.cpp =================================================================== --- test/scudo/interface.cpp +++ test/scudo/interface.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t ownership 2>&1 // RUN: %run %t ownership-and-size 2>&1 // RUN: %run %t heap-size 2>&1 Index: test/scudo/lit.cfg =================================================================== --- test/scudo/lit.cfg +++ test/scudo/lit.cfg @@ -11,21 +11,24 @@ # Path to the shared & static libraries shared_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.so" % config.target_arch) static_libscudo = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo-%s.a" % config.target_arch) +static_libscudo_cxx = os.path.join(config.compiler_rt_libdir, "libclang_rt.scudo_cxx-%s.a" % config.target_arch) + whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo +whole_archive_cxx = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % static_libscudo_cxx # Test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] -# C flags. +# C & CXX flags. c_flags = ([config.target_cflags] + - ["-std=c++11", - "-pthread", + ["-pthread", "-fPIE", "-pie", "-O0", "-UNDEBUG", "-ldl", "-Wl,--gc-sections"]) +cxx_flags = (config.cxx_mode_flags + c_flags + ["-std=c++11"]) # Android doesn't want -lrt. if not config.android: @@ -37,6 +40,7 @@ # Add clang substitutions. config.substitutions.append(("%clang ", build_invocation(c_flags))) config.substitutions.append(("%clang_scudo ", build_invocation(c_flags) + whole_archive)) +config.substitutions.append(("%clangxx_scudo ", build_invocation(cxx_flags) + whole_archive + whole_archive_cxx)) config.substitutions.append(("%shared_libscudo", shared_libscudo)) # Platform-specific default SCUDO_OPTIONS for lit tests. Index: test/scudo/malloc.cpp =================================================================== --- test/scudo/malloc.cpp +++ test/scudo/malloc.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t 2>&1 // Tests that a regular workflow of allocation, memory fill and free works as Index: test/scudo/memalign.c =================================================================== --- test/scudo/memalign.c +++ test/scudo/memalign.c @@ -15,11 +15,11 @@ #include // Sometimes the headers may not have this... -extern "C" void *aligned_alloc(size_t alignment, size_t size); +void *aligned_alloc(size_t alignment, size_t size); int main(int argc, char **argv) { - void *p = nullptr; + void *p = NULL; size_t alignment = 1U << 12; size_t size = 1U << 12; int err; Index: test/scudo/memalign.cpp =================================================================== --- test/scudo/memalign.cpp +++ test/scudo/memalign.cpp @@ -1,81 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// 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 - -// Tests that the various aligned allocation functions work as intended. Also -// tests for the condition where the alignment is not a power of 2. - -#include -#include -#include -#include -#include -#include -#include - -// Sometimes the headers may not have this... -extern "C" void *aligned_alloc(size_t alignment, size_t size); - -int main(int argc, char **argv) -{ - void *p = nullptr; - size_t alignment = 1U << 12; - size_t size = 1U << 12; - int err; - - assert(argc == 2); - - if (!strcmp(argv[1], "valid")) { - posix_memalign(&p, alignment, size); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - p = aligned_alloc(alignment, size); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - // Tests various combinations of alignment and sizes - for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { - alignment = 1U << i; - for (int j = 1; j < 33; j++) { - size = 0x800 * j; - for (int k = 0; k < 3; k++) { - p = memalign(alignment, size - (2 * sizeof(void *) * k)); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - } - } - } - // For larger alignment, reduce the number of allocations to avoid running - // out of potential addresses (on 32-bit). - for (int i = 19; i <= 24; i++) { - for (int k = 0; k < 3; k++) { - p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); - assert(p); - assert(((uintptr_t)p & (alignment - 1)) == 0); - free(p); - } - } - } - if (!strcmp(argv[1], "invalid")) { - // Alignment is not a power of 2. - p = memalign(alignment - 1, size); - assert(!p); - // Size is not a multiple of alignment. - p = aligned_alloc(alignment, size >> 1); - assert(!p); - void *p_unchanged = (void *)0x42UL; - p = p_unchanged; - // Alignment is not a power of 2. - err = posix_memalign(&p, 3, size); - assert(p == p_unchanged); - assert(err == EINVAL); - // Alignment is a power of 2, but not a multiple of size(void *). - err = posix_memalign(&p, 2, size); - assert(p == p_unchanged); - assert(err == EINVAL); - } - return 0; -} Index: test/scudo/mismatch.cpp =================================================================== --- test/scudo/mismatch.cpp +++ test/scudo/mismatch.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t mallocdel 2>&1 | FileCheck --check-prefix=CHECK-dealloc %s // 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 Index: test/scudo/options.cpp =================================================================== --- test/scudo/options.cpp +++ test/scudo/options.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: %run %t 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=0 %run %t 2>&1 // RUN: %env_scudo_opts=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s Index: test/scudo/overflow.cpp =================================================================== --- test/scudo/overflow.cpp +++ test/scudo/overflow.cpp @@ -1,39 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: not %run %t malloc 2>&1 | FileCheck %s -// RUN: %env_scudo_opts=QuarantineSizeKb=64 not %run %t quarantine 2>&1 | FileCheck %s - -// Tests that header corruption of an allocated or quarantined chunk is caught. - -#include -#include -#include - -int main(int argc, char **argv) -{ - ssize_t offset = sizeof(void *) == 8 ? 8 : 0; - - assert(argc == 2); - - if (!strcmp(argv[1], "malloc")) { - // Simulate a header corruption of an allocated chunk (1-bit) - void *p = malloc(1U << 4); - assert(p); - ((char *)p)[-(offset + 1)] ^= 1; - free(p); - } - if (!strcmp(argv[1], "quarantine")) { - void *p = malloc(1U << 4); - assert(p); - free(p); - // Simulate a header corruption of a quarantined chunk - ((char *)p)[-(offset + 2)] ^= 1; - // Trigger the quarantine recycle - for (int i = 0; i < 0x100; i++) { - p = malloc(1U << 8); - free(p); - } - } - return 0; -} - -// CHECK: ERROR: corrupted chunk header at address Index: test/scudo/preinit.c =================================================================== --- test/scudo/preinit.c +++ test/scudo/preinit.c @@ -12,7 +12,7 @@ #include #include -static void *global_p = nullptr; +static void *global_p = NULL; void __init(void) { global_p = malloc(1); Index: test/scudo/preinit.cpp =================================================================== --- test/scudo/preinit.cpp +++ test/scudo/preinit.cpp @@ -1,40 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t 2>&1 - -// Verifies that calling malloc in a preinit_array function succeeds, and that -// the resulting pointer can be freed at program termination. - -// On some Android versions, calling mmap() from a preinit function segfaults. -// It looks like __mmap2.S ends up calling a NULL function pointer. -// UNSUPPORTED: android - -#include -#include -#include - -static void *global_p = nullptr; - -void __init(void) { - global_p = malloc(1); - if (!global_p) - exit(1); -} - -void __fini(void) { - if (global_p) - free(global_p); -} - -int main(int argc, char **argv) -{ - void *p = malloc(1); - assert(p); - free(p); - - return 0; -} - -__attribute__((section(".preinit_array"), used)) - void (*__local_preinit)(void) = __init; -__attribute__((section(".fini_array"), used)) - void (*__local_fini)(void) = __fini; Index: test/scudo/preload.cpp =================================================================== --- test/scudo/preload.cpp +++ test/scudo/preload.cpp @@ -1,20 +0,0 @@ -// Test that the preloaded runtime works without linking the static library. - -// RUN: %clang %s -o %t -// 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 - -#include -#include - -int main(int argc, char *argv[]) { - void *p = malloc(sizeof(int)); - assert(p); - free(p); - free(p); - return 0; -} - -// CHECK: ERROR: invalid chunk state Index: test/scudo/quarantine.c =================================================================== --- test/scudo/quarantine.c +++ test/scudo/quarantine.c @@ -61,7 +61,7 @@ free(p); // Eventually the chunk should become available again. - bool found = false; + char found = 0; for (int i = 0; i < 0x200 && !found; i++) { p = malloc(size); assert(p); Index: test/scudo/quarantine.cpp =================================================================== --- test/scudo/quarantine.cpp +++ test/scudo/quarantine.cpp @@ -1,124 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineSizeKb=64" not %run %t unused 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineChunksUpToSize=256" not %run %t unused 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0" %run %t zeroquarantine 2>&1 -// RUN: %env_scudo_opts=QuarantineSizeKb=64 %run %t smallquarantine 2>&1 -// RUN: %env_scudo_opts=QuarantineChunksUpToSize=256 %run %t threshold 2>&1 -// RUN: %env_scudo_opts="QuarantineSizeMb=1" %run %t oldquarantine 2>&1 - -// Tests that the quarantine prevents a chunk from being reused right away. -// Also tests that a chunk will eventually become available again for -// allocation when the recycling criteria has been met. Finally, tests the -// threshold up to which a chunk is quarantine, and the old quarantine behavior. - -#include -#include -#include -#include - -#include - -int main(int argc, char **argv) -{ - void *p, *old_p; - size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8; - - assert(argc == 2); - // First, warm up the allocator for the classes used. - p = malloc(size); - assert(p); - free(p); - p = malloc(size + 1); - assert(p); - free(p); - assert(posix_memalign(&p, alignment, size) == 0); - assert(p); - free(p); - assert(posix_memalign(&p, alignment, size + 1) == 0); - assert(p); - free(p); - - if (!strcmp(argv[1], "zeroquarantine")) { - // Verifies that a chunk is deallocated right away when the local and - // global quarantine sizes are 0. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - } - if (!strcmp(argv[1], "smallquarantine")) { - // The delayed freelist will prevent a chunk from being available right - // away. - p = malloc(size); - assert(p); - old_p = p; - free(p); - p = malloc(size); - assert(p); - assert(old_p != p); - free(p); - - // Eventually the chunk should become available again. - bool found = false; - for (int i = 0; i < 0x200 && !found; i++) { - p = malloc(size); - assert(p); - found = (p == old_p); - free(p); - } - assert(found); - } - if (!strcmp(argv[1], "threshold")) { - // Verifies that a chunk of size greater than the threshold will be freed - // right away. Alignment has no impact on the threshold. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size + 1); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - assert(posix_memalign(&p, alignment, size + 1) == 0); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes); - // Verifies that a chunk of size lower or equal to the threshold will be - // quarantined. - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - assert(posix_memalign(&p, alignment, size) == 0); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - } - if (!strcmp(argv[1], "oldquarantine")) { - // Verifies that we quarantine everything if the deprecated quarantine - // option is specified. Alignment has no impact on the threshold. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(size); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - assert(posix_memalign(&p, alignment, size) == 0); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - // Secondary backed allocation. - allocated_bytes = __sanitizer_get_current_allocated_bytes(); - p = malloc(1U << 19); - assert(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - free(p); - assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes); - } - - return 0; -} Index: test/scudo/random_shuffle.cpp =================================================================== --- test/scudo/random_shuffle.cpp +++ test/scudo/random_shuffle.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -o %t +// RUN: %clangxx_scudo %s -o %t // RUN: rm -rf %T/random_shuffle_tmp_dir // RUN: mkdir %T/random_shuffle_tmp_dir // RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out1 Index: test/scudo/realloc.cpp =================================================================== --- test/scudo/realloc.cpp +++ test/scudo/realloc.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %run %t pointers 2>&1 // RUN: %run %t contents 2>&1 // RUN: %run %t usablesize 2>&1 Index: test/scudo/secondary.c =================================================================== --- test/scudo/secondary.c +++ test/scudo/secondary.c @@ -36,7 +36,7 @@ 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, nullptr); + sigaction(SIGSEGV, &a, NULL); if (!strcmp(argv[1], "after")) { for (int i = 0; i < page_size; i++) p[size + i] = 'A'; Index: test/scudo/secondary.cpp =================================================================== --- test/scudo/secondary.cpp +++ test/scudo/secondary.cpp @@ -1,53 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t after 2>&1 | FileCheck %s -// RUN: %run %t before 2>&1 | FileCheck %s - -// Test that we hit a guard page when writing past the end of a chunk -// allocated by the Secondary allocator, or writing too far in front of it. - -#include -#include -#include -#include -#include -#include - -void handler(int signo, siginfo_t *info, void *uctx) { - if (info->si_code == SEGV_ACCERR) { - fprintf(stderr, "SCUDO SIGSEGV\n"); - exit(0); - } - exit(1); -} - -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; - - 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. - sigaction(SIGSEGV, &a, nullptr); - if (!strcmp(argv[1], "after")) { - for (int i = 0; i < page_size; i++) - p[size + i] = 'A'; - } - if (!strcmp(argv[1], "before")) { - for (int i = 1; i < page_size; i++) - p[-i] = 'A'; - } - free(p); - - return 1; // A successful test means we shouldn't reach this. -} - -// CHECK: SCUDO SIGSEGV Index: test/scudo/sized-delete.cpp =================================================================== --- test/scudo/sized-delete.cpp +++ test/scudo/sized-delete.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo -fsized-deallocation %s -o %t +// RUN: %clangxx_scudo -fsized-deallocation %s -o %t // RUN: %env_scudo_opts=DeleteSizeMismatch=1 %run %t gooddel 2>&1 // RUN: %env_scudo_opts=DeleteSizeMismatch=1 not %run %t baddel 2>&1 | FileCheck %s // RUN: %env_scudo_opts=DeleteSizeMismatch=0 %run %t baddel 2>&1 Index: test/scudo/sizes.cpp =================================================================== --- test/scudo/sizes.cpp +++ test/scudo/sizes.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_scudo %s -lstdc++ -o %t +// RUN: %clangxx_scudo %s -lstdc++ -o %t // RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s // RUN: %env_scudo_opts=allocator_may_return_null=1 %run %t malloc 2>&1 // RUN: %env_scudo_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s Index: test/scudo/threads.c =================================================================== --- test/scudo/threads.c +++ test/scudo/threads.c @@ -20,7 +20,7 @@ pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -bool go = false; +char go = 0; void *thread_fun(void *arg) { pthread_mutex_lock(&mutex); @@ -51,7 +51,7 @@ for (int i = 0; i < num_threads; i++) pthread_create(&tid[i], 0, thread_fun, 0); pthread_mutex_lock(&mutex); - go = true; + go = 1; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex); for (int i = 0; i < num_threads; i++) Index: test/scudo/threads.cpp =================================================================== --- test/scudo/threads.cpp +++ test/scudo/threads.cpp @@ -1,65 +0,0 @@ -// 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 - -// 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 -#include -#include -#include - -#include - -int num_threads; -int total_num_alloc; -const int kMaxNumThreads = 500; -pthread_t tid[kMaxNumThreads]; - -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -bool go = false; - -void *thread_fun(void *arg) { - pthread_mutex_lock(&mutex); - while (!go) pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - 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()); - - for (int i = 0; i < num_threads; i++) - pthread_create(&tid[i], 0, thread_fun, 0); - pthread_mutex_lock(&mutex); - go = true; - pthread_cond_broadcast(&cond); - pthread_mutex_unlock(&mutex); - for (int i = 0; i < num_threads; i++) - pthread_join(tid[i], 0); - - 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: test/scudo/tsd_destruction.cpp =================================================================== --- test/scudo/tsd_destruction.cpp +++ test/scudo/tsd_destruction.cpp @@ -1,42 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// RUN: %run %t 2>&1 - -#include -#include -#include -#include -#include - -// Some of glibc's own thread local data is destroyed after a user's thread -// local destructors are called, via __libc_thread_freeres. This might involve -// calling free, as is the case for strerror_thread_freeres. -// If there is no prior heap operation in the thread, this free would end up -// initializing some thread specific data that would never be destroyed -// properly, while still being deallocated when the TLS goes away. As a result, -// a program could SEGV, usually in -// __sanitizer::AllocatorGlobalStats::Unregister, where one of the doubly -// linked list links would refer to a now unmapped memory area. - -// This test reproduces those circumstances. Success means executing without -// a segmentation fault. - -const int kNumThreads = 16; -pthread_t tid[kNumThreads]; - -void *thread_func(void *arg) { - uintptr_t i = (uintptr_t)arg; - if ((i & 1) == 0) free(malloc(16)); - // Calling strerror_l allows for strerror_thread_freeres to be called. - strerror_l(0, LC_GLOBAL_LOCALE); - return 0; -} - -int main(int argc, char** argv) { - for (uintptr_t j = 0; j < 8; j++) { - for (uintptr_t i = 0; i < kNumThreads; i++) - pthread_create(&tid[i], 0, thread_func, (void *)i); - for (uintptr_t i = 0; i < kNumThreads; i++) - pthread_join(tid[i], 0); - } - return 0; -} Index: test/scudo/valloc.c =================================================================== --- test/scudo/valloc.c +++ test/scudo/valloc.c @@ -19,7 +19,7 @@ int main(int argc, char **argv) { - void *p = nullptr; + void *p = NULL; size_t size, page_size; assert(argc == 2); Index: test/scudo/valloc.cpp =================================================================== --- test/scudo/valloc.cpp +++ test/scudo/valloc.cpp @@ -1,65 +0,0 @@ -// RUN: %clang_scudo %s -o %t -// 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, armhf-linux - -// Tests that valloc and pvalloc work as intended. - -#include -#include -#include -#include -#include -#include - -size_t round_up_to(size_t size, size_t alignment) { - return (size + alignment - 1) & ~(alignment - 1); -} - -int main(int argc, char **argv) -{ - void *p = nullptr; - size_t size, page_size; - - assert(argc == 2); - - page_size = sysconf(_SC_PAGESIZE); - // Check that the page size is a power of two. - assert((page_size & (page_size - 1)) == 0); - - if (!strcmp(argv[1], "valid")) { - for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 21; i++) { - size = 1U << i; - p = valloc(size - (2 * sizeof(void *))); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - free(p); - p = pvalloc(size - (2 * sizeof(void *))); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - assert(malloc_usable_size(p) >= round_up_to(size, page_size)); - free(p); - p = valloc(size); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - free(p); - p = pvalloc(size); - assert(p); - assert(((uintptr_t)p & (page_size - 1)) == 0); - assert(malloc_usable_size(p) >= round_up_to(size, page_size)); - free(p); - } - } - if (!strcmp(argv[1], "invalid")) { - // Size passed to pvalloc overflows when rounded up. - p = pvalloc((size_t)-1); - assert(!p); - assert(errno == ENOMEM); - errno = 0; - p = pvalloc((size_t)-page_size); - assert(!p); - assert(errno == ENOMEM); - } - return 0; -}