summaryrefslogtreecommitdiff
path: root/test/scudo
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:27 +0000
commit316d58822dada9440bd06ecfc758dcc2364d617c (patch)
treefe72ec2e6ce9a360dda74d9d57f7acdb0e3c39d6 /test/scudo
parent0230fcf22fe7d19f03d981c9c2c59a3db0b72ea5 (diff)
Notes
Diffstat (limited to 'test/scudo')
-rw-r--r--test/scudo/CMakeLists.txt31
-rw-r--r--test/scudo/alignment.cpp7
-rw-r--r--test/scudo/double-free.cpp2
-rw-r--r--test/scudo/interface.cpp28
-rw-r--r--test/scudo/lit.cfg13
-rw-r--r--test/scudo/lit.site.cfg.in4
-rw-r--r--test/scudo/malloc.cpp27
-rw-r--r--test/scudo/memalign.cpp41
-rw-r--r--test/scudo/mismatch.cpp2
-rw-r--r--test/scudo/options.cpp25
-rw-r--r--test/scudo/overflow.cpp5
-rw-r--r--test/scudo/preinit.cpp1
-rw-r--r--test/scudo/random_shuffle.cpp24
-rw-r--r--test/scudo/realloc.cpp90
-rw-r--r--test/scudo/secondary.cpp54
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