diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:27 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:27 +0000 |
commit | 316d58822dada9440bd06ecfc758dcc2364d617c (patch) | |
tree | fe72ec2e6ce9a360dda74d9d57f7acdb0e3c39d6 /test/scudo | |
parent | 0230fcf22fe7d19f03d981c9c2c59a3db0b72ea5 (diff) |
Notes
Diffstat (limited to 'test/scudo')
-rw-r--r-- | test/scudo/CMakeLists.txt | 31 | ||||
-rw-r--r-- | test/scudo/alignment.cpp | 7 | ||||
-rw-r--r-- | test/scudo/double-free.cpp | 2 | ||||
-rw-r--r-- | test/scudo/interface.cpp | 28 | ||||
-rw-r--r-- | test/scudo/lit.cfg | 13 | ||||
-rw-r--r-- | test/scudo/lit.site.cfg.in | 4 | ||||
-rw-r--r-- | test/scudo/malloc.cpp | 27 | ||||
-rw-r--r-- | test/scudo/memalign.cpp | 41 | ||||
-rw-r--r-- | test/scudo/mismatch.cpp | 2 | ||||
-rw-r--r-- | test/scudo/options.cpp | 25 | ||||
-rw-r--r-- | test/scudo/overflow.cpp | 5 | ||||
-rw-r--r-- | test/scudo/preinit.cpp | 1 | ||||
-rw-r--r-- | test/scudo/random_shuffle.cpp | 24 | ||||
-rw-r--r-- | test/scudo/realloc.cpp | 90 | ||||
-rw-r--r-- | test/scudo/secondary.cpp | 54 |
15 files changed, 268 insertions, 86 deletions
diff --git a/test/scudo/CMakeLists.txt b/test/scudo/CMakeLists.txt index b6cb2fd24f012..a8990999722e1 100644 --- a/test/scudo/CMakeLists.txt +++ b/test/scudo/CMakeLists.txt @@ -1,6 +1,7 @@ set(SCUDO_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SCUDO_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(SCUDO_TESTSUITES) set(SCUDO_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -12,17 +13,21 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg ) -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO) - STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO}) - STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE) -endif(CMAKE_SYSTEM_NAME MATCHES "Linux") +set(SCUDO_TEST_ARCH ${SCUDO_SUPPORTED_ARCH}) +foreach(arch ${SCUDO_TEST_ARCH}) + set(SCUDO_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" SCUDO_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} SCUDO_TEST_TARGET_CC SCUDO_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) -if (SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8) - add_lit_testsuite(check-scudo - "Running the Scudo Hardened Allocator tests" - ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${SCUDO_TEST_DEPS}) - set_target_properties(check-scudo PROPERTIES FOLDER - "Compiler-RT Misc") -endif(SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND SCUDO_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +add_lit_testsuite(check-scudo "Running the Scudo Hardened Allocator tests" + ${SCUDO_TESTSUITES} + DEPENDS ${SCUDO_TEST_DEPS}) +set_target_properties(check-scudo PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/scudo/alignment.cpp b/test/scudo/alignment.cpp index c5e57d1799079..a6eca87a82248 100644 --- a/test/scudo/alignment.cpp +++ b/test/scudo/alignment.cpp @@ -1,11 +1,10 @@ // RUN: %clang_scudo %s -o %t // RUN: not %run %t pointers 2>&1 | FileCheck %s -// Tests that a non-16-byte aligned pointer will trigger the associated error -// on deallocation. +// Tests that a non MinAlignment aligned pointer will trigger the associated +// error on deallocation. #include <assert.h> -#include <malloc.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -17,7 +16,7 @@ int main(int argc, char **argv) void *p = malloc(1U << 16); if (!p) return 1; - free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 8)); + free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 1)); } return 0; } diff --git a/test/scudo/double-free.cpp b/test/scudo/double-free.cpp index 4f5bf0cb8e56a..75919f0c459c5 100644 --- a/test/scudo/double-free.cpp +++ b/test/scudo/double-free.cpp @@ -46,4 +46,4 @@ int main(int argc, char **argv) return 0; } -// CHECK: ERROR: invalid chunk state when deallocating address +// CHECK: ERROR: invalid chunk state diff --git a/test/scudo/interface.cpp b/test/scudo/interface.cpp new file mode 100644 index 0000000000000..f9353066efa37 --- /dev/null +++ b/test/scudo/interface.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 + +// Tests that the sanitizer interface functions behave appropriately. + +#include <stdlib.h> + +#include <vector> + +#include <sanitizer/allocator_interface.h> + +int main(int argc, char **argv) +{ + void *p; + std::vector<ssize_t> sizes{1, 8, 16, 32, 1024, 32768, + 1 << 16, 1 << 17, 1 << 20, 1 << 24}; + for (size_t size : sizes) { + p = malloc(size); + if (!p) + return 1; + if (!__sanitizer_get_ownership(p)) + return 1; + if (__sanitizer_get_allocated_size(p) < size) + return 1; + free(p); + } + return 0; +} diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index e2a4997dd3c28..4eff2ce2191d0 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -3,7 +3,7 @@ import os # Setup config name. -config.name = 'Scudo' +config.name = 'Scudo' + config.name_suffix # Setup source root. config.test_source_root = os.path.dirname(__file__) @@ -14,18 +14,19 @@ base_lib = os.path.join(config.compiler_rt_libdir, whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % base_lib # Test suffixes. -config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test'] +config.suffixes = ['.c', '.cc', '.cpp'] # C flags. -c_flags = ["-std=c++11", +c_flags = ([config.target_cflags] + + ["-std=c++11", "-lstdc++", - "-ldl", "-lrt", - "-pthread", "-latomic", + "-ldl", + "-pthread", "-fPIE", "-pie", - "-O0"] + "-O0"]) def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " diff --git a/test/scudo/lit.site.cfg.in b/test/scudo/lit.site.cfg.in index 64e2fb39eed8a..4299518755e98 100644 --- a/test/scudo/lit.site.cfg.in +++ b/test/scudo/lit.site.cfg.in @@ -1,5 +1,9 @@ @LIT_SITE_CFG_IN_HEADER@ +config.name_suffix = "@SCUDO_TEST_CONFIG_SUFFIX@" +config.target_arch = "@SCUDO_TEST_TARGET_ARCH@" +config.target_cflags = "@SCUDO_TEST_TARGET_CFLAGS@" + # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/test/scudo/malloc.cpp b/test/scudo/malloc.cpp index 4507a5225ceb7..cafc744a20c24 100644 --- a/test/scudo/malloc.cpp +++ b/test/scudo/malloc.cpp @@ -2,26 +2,37 @@ // RUN: %run %t 2>&1 // Tests that a regular workflow of allocation, memory fill and free works as -// intended. Also tests that a zero-sized allocation succeeds. +// intended. Tests various sizes serviced by the primary and secondary +// allocators. -#include <malloc.h> #include <stdlib.h> #include <string.h> +#include <vector> + int main(int argc, char **argv) { void *p; - size_t size = 1U << 8; + std::vector<ssize_t> sizes{1, 8, 16, 32, 1024, 32768, + 1 << 16, 1 << 17, 1 << 20, 1 << 24}; + std::vector<int> offsets{1, 0, -1, -7, -8, -15, -16, -31, -32}; - p = malloc(size); - if (!p) - return 1; - memset(p, 'A', size); - free(p); p = malloc(0); if (!p) return 1; free(p); + for (ssize_t size : sizes) { + for (int offset: offsets) { + ssize_t actual_size = size + offset; + if (actual_size <= 0) + continue; + p = malloc(actual_size); + if (!p) + return 1; + memset(p, 0xff, actual_size); + free(p); + } + } return 0; } diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 951d1aade6ec9..b407ec5743490 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -10,22 +10,24 @@ #include <stdlib.h> #include <string.h> +// Reduce the size of the quarantine, or the test can run out of aligned memory +// on 32-bit for the larger alignments. +extern "C" const char *__scudo_default_options() { + return "QuarantineSizeMb=1"; +} + // 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; + void *p = nullptr; size_t alignment = 1U << 12; - size_t size = alignment; + size_t size = 1U << 12; assert(argc == 2); + if (!strcmp(argv[1], "valid")) { - p = memalign(alignment, size); - if (!p) - return 1; - free(p); - p = nullptr; posix_memalign(&p, alignment, size); if (!p) return 1; @@ -34,6 +36,29 @@ int main(int argc, char **argv) if (!p) return 1; 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)); + if (!p) + return 1; + 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)); + if (!p) + return 1; + free(p); + } + } } if (!strcmp(argv[1], "invalid")) { p = memalign(alignment - 1, size); @@ -42,4 +67,4 @@ int main(int argc, char **argv) return 0; } -// CHECK: ERROR: malloc alignment is not a power of 2 +// CHECK: ERROR: alignment is not a power of 2 diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index 2d3d198af640a..54cdafc86ee67 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -30,7 +30,7 @@ int main(int argc, char **argv) free((void *)p); } if (!strcmp(argv[1], "memaligndel")) { - int *p = (int *)memalign(0x10, 0x10); + int *p = (int *)memalign(16, 16); if (!p) return 1; delete p; diff --git a/test/scudo/options.cpp b/test/scudo/options.cpp new file mode 100644 index 0000000000000..bccf7c8fbd2b9 --- /dev/null +++ b/test/scudo/options.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s + +// Tests that the options can be passed using getScudoDefaultOptions, and that +// the environment ones take precedence over them. + +#include <stdlib.h> +#include <malloc.h> + +extern "C" const char* __scudo_default_options() { + return "DeallocationTypeMismatch=0"; // Defaults to true in scudo_flags.inc. +} + +int main(int argc, char **argv) +{ + int *p = (int *)malloc(16); + if (!p) + return 1; + delete p; + return 0; +} + +// CHECK: ERROR: allocation type mismatch on address diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp index 5b2cb7560133a..c93a544ea0a07 100644 --- a/test/scudo/overflow.cpp +++ b/test/scudo/overflow.cpp @@ -11,12 +11,13 @@ int main(int argc, char **argv) { assert(argc == 2); + ssize_t offset = sizeof(void *) == 8 ? 8 : 0; if (!strcmp(argv[1], "malloc")) { // Simulate a header corruption of an allocated chunk (1-bit) void *p = malloc(1U << 4); if (!p) return 1; - ((char *)p)[-1] ^= 1; + ((char *)p)[-(offset + 1)] ^= 1; free(p); } if (!strcmp(argv[1], "quarantine")) { @@ -25,7 +26,7 @@ int main(int argc, char **argv) return 1; free(p); // Simulate a header corruption of a quarantined chunk - ((char *)p)[-2] ^= 1; + ((char *)p)[-(offset + 2)] ^= 1; // Trigger the quarantine recycle for (int i = 0; i < 0x100; i++) { p = malloc(1U << 16); diff --git a/test/scudo/preinit.cpp b/test/scudo/preinit.cpp index a280ae1d440a9..34f61c9ddfbb4 100644 --- a/test/scudo/preinit.cpp +++ b/test/scudo/preinit.cpp @@ -4,7 +4,6 @@ // Verifies that calling malloc in a preinit_array function succeeds, and that // the resulting pointer can be freed at program termination. -#include <malloc.h> #include <stdlib.h> #include <string.h> diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp new file mode 100644 index 0000000000000..fce522d9481c6 --- /dev/null +++ b/test/scudo/random_shuffle.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_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 +// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out2 +// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out1 +// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 +// RUN: not diff %T/random_shuffle_tmp_dir/out? +// RUN: rm -rf %T/random_shuffle_tmp_dir +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux + +// Tests that the allocator shuffles the chunks before returning to the user. + +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char **argv) { + int alloc_size = argc == 2 ? atoi(argv[1]) : 100; + char *base = new char[alloc_size]; + for (int i = 0; i < 20; i++) { + char *p = new char[alloc_size]; + printf("%zd\n", base - p); + } +} diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp index 2a7d5b69f5f20..cc44595001f43 100644 --- a/test/scudo/realloc.cpp +++ b/test/scudo/realloc.cpp @@ -14,54 +14,60 @@ #include <malloc.h> #include <string.h> +#include <vector> + int main(int argc, char **argv) { void *p, *old_p; - size_t size = 32; + // Those sizes will exercise both allocators (Primary & Secondary). + std::vector<size_t> sizes{1, 16, 1024, 32768, 1 << 16, 1 << 17, 1 << 20}; assert(argc == 2); - if (!strcmp(argv[1], "pointers")) { - old_p = p = realloc(nullptr, size); - if (!p) - return 1; - size = malloc_usable_size(p); - // Our realloc implementation will return the same pointer if the size - // requested is lower or equal to the usable size of the associated chunk. - p = realloc(p, size - 1); - if (p != old_p) - return 1; - p = realloc(p, size); - if (p != old_p) - return 1; - // And a new one if the size is greater. - p = realloc(p, size + 1); - if (p == old_p) - return 1; - // A size of 0 will free the chunk and return nullptr. - p = realloc(p, 0); - if (p) - return 1; - old_p = nullptr; - } - if (!strcmp(argv[1], "contents")) { - p = realloc(nullptr, size); - if (!p) - return 1; - for (int i = 0; i < size; i++) - reinterpret_cast<char *>(p)[i] = 'A'; - p = realloc(p, size + 1); - // The contents of the reallocated chunk must match the original one. - for (int i = 0; i < size; i++) - if (reinterpret_cast<char *>(p)[i] != 'A') + for (size_t size : sizes) { + if (!strcmp(argv[1], "pointers")) { + old_p = p = realloc(nullptr, size); + if (!p) return 1; - } - if (!strcmp(argv[1], "memalign")) { - // A chunk coming from memalign cannot be reallocated. - p = memalign(16, size); - if (!p) - return 1; - p = realloc(p, size); - free(p); + size = malloc_usable_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. + p = realloc(p, size - 1); + if (p != old_p) + return 1; + p = realloc(p, size); + if (p != old_p) + return 1; + // And a new one if the size is greater. + p = realloc(p, size + 1); + if (p == old_p) + return 1; + // A size of 0 will free the chunk and return nullptr. + p = realloc(p, 0); + if (p) + return 1; + old_p = nullptr; + } + if (!strcmp(argv[1], "contents")) { + p = realloc(nullptr, size); + if (!p) + return 1; + for (int i = 0; i < size; i++) + reinterpret_cast<char *>(p)[i] = 'A'; + p = realloc(p, size + 1); + // The contents of the reallocated chunk must match the original one. + for (int i = 0; i < size; i++) + if (reinterpret_cast<char *>(p)[i] != 'A') + return 1; + } + if (!strcmp(argv[1], "memalign")) { + // A chunk coming from memalign cannot be reallocated. + p = memalign(16, size); + if (!p) + return 1; + p = realloc(p, size); + free(p); + } } return 0; } diff --git a/test/scudo/secondary.cpp b/test/scudo/secondary.cpp new file mode 100644 index 0000000000000..7a634a81eb03e --- /dev/null +++ b/test/scudo/secondary.cpp @@ -0,0 +1,54 @@ +// 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 <malloc.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <assert.h> + +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); + if (!p) + return 1; + 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 |