diff options
Diffstat (limited to 'lib/dfsan/lit_tests')
-rw-r--r-- | lib/dfsan/lit_tests/CMakeLists.txt | 21 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/Inputs/flags_abilist.txt | 10 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/basic.c | 21 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/custom.c | 154 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/flags.c | 24 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/fncall.c | 26 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/lit.cfg | 69 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/lit.site.cfg.in | 5 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/propagate.c | 47 |
9 files changed, 377 insertions, 0 deletions
diff --git a/lib/dfsan/lit_tests/CMakeLists.txt b/lib/dfsan/lit_tests/CMakeLists.txt new file mode 100644 index 0000000000000..d7c5c82ac3c0f --- /dev/null +++ b/lib/dfsan/lit_tests/CMakeLists.txt @@ -0,0 +1,21 @@ +set(DFSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..) +set(DFSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg) + +if(COMPILER_RT_CAN_EXECUTE_TESTS) + # Run DFSan tests only if we're sure we may produce working binaries. + set(DFSAN_TEST_DEPS + ${SANITIZER_COMMON_LIT_TEST_DEPS} + ${DFSAN_RUNTIME_LIBRARIES} + dfsan_abilist) + set(DFSAN_TEST_PARAMS + dfsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg) + add_lit_testsuite(check-dfsan "Running the DataFlowSanitizer tests" + ${CMAKE_CURRENT_BINARY_DIR} + PARAMS ${DFSAN_TEST_PARAMS} + DEPENDS ${DFSAN_TEST_DEPS}) + set_target_properties(check-dfsan PROPERTIES FOLDER "DFSan tests") +endif() diff --git a/lib/dfsan/lit_tests/Inputs/flags_abilist.txt b/lib/dfsan/lit_tests/Inputs/flags_abilist.txt new file mode 100644 index 0000000000000..94b1fa2982599 --- /dev/null +++ b/lib/dfsan/lit_tests/Inputs/flags_abilist.txt @@ -0,0 +1,10 @@ +fun:f=uninstrumented + +fun:main=uninstrumented +fun:main=discard + +fun:dfsan_create_label=uninstrumented +fun:dfsan_create_label=discard + +fun:dfsan_set_label=uninstrumented +fun:dfsan_set_label=discard diff --git a/lib/dfsan/lit_tests/basic.c b/lib/dfsan/lit_tests/basic.c new file mode 100644 index 0000000000000..b566c9271d0b4 --- /dev/null +++ b/lib/dfsan/lit_tests/basic.c @@ -0,0 +1,21 @@ +// RUN: %clang_dfsan -m64 %s -o %t && %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t + +// Tests that labels are propagated through loads and stores. + +#include <sanitizer/dfsan_interface.h> +#include <assert.h> + +int main(void) { + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + dfsan_label new_label = dfsan_get_label(i); + assert(i_label == new_label); + + dfsan_label read_label = dfsan_read_label(&i, sizeof(i)); + assert(i_label == read_label); + + return 0; +} diff --git a/lib/dfsan/lit_tests/custom.c b/lib/dfsan/lit_tests/custom.c new file mode 100644 index 0000000000000..c9fa9356154df --- /dev/null +++ b/lib/dfsan/lit_tests/custom.c @@ -0,0 +1,154 @@ +// RUN: %clang_dfsan -m64 %s -o %t && %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t + +// Tests custom implementations of various libc functions. + +#define _GNU_SOURCE +#include <sanitizer/dfsan_interface.h> +#include <assert.h> +#include <link.h> +#include <pthread.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +void *ptcb(void *p) { + assert(p == (void *)1); + assert(dfsan_get_label((uintptr_t)p) == 0); + return (void *)2; +} + +int dlcb(struct dl_phdr_info *info, size_t size, void *data) { + assert(data == (void *)3); + assert(dfsan_get_label((uintptr_t)info) == 0); + assert(dfsan_get_label(size) == 0); + assert(dfsan_get_label((uintptr_t)data) == 0); + return 0; +} + +int main(void) { + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + int j = 2; + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_set_label(j_label, &j, sizeof(j)); + + struct stat s; + s.st_dev = i; + int rv = stat("/", &s); + assert(rv == 0); + assert(dfsan_get_label(s.st_dev) == 0); + + s.st_dev = i; + rv = stat("/nonexistent", &s); + assert(rv == -1); + assert(dfsan_get_label(s.st_dev) == i_label); + + int fd = open("/dev/zero", O_RDONLY); + s.st_dev = i; + rv = fstat(fd, &s); + assert(rv == 0); + assert(dfsan_get_label(s.st_dev) == 0); + + char str1[] = "str1", str2[] = "str2"; + dfsan_set_label(i_label, &str1[3], 1); + dfsan_set_label(j_label, &str2[3], 1); + + rv = memcmp(str1, str2, sizeof(str1)); + assert(rv < 0); + assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label)); + + char strc[sizeof(str1)]; + memcpy(strc, str1, sizeof(str1)); + assert(dfsan_get_label(strc[0]) == 0); + assert(dfsan_get_label(strc[3]) == i_label); + + memset(strc, j, sizeof(strc)); + assert(dfsan_get_label(strc[0]) == j_label); + assert(dfsan_get_label(strc[1]) == j_label); + assert(dfsan_get_label(strc[2]) == j_label); + assert(dfsan_get_label(strc[3]) == j_label); + assert(dfsan_get_label(strc[4]) == j_label); + + rv = strcmp(str1, str2); + assert(rv < 0); + assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label)); + + char *strd = strdup(str1); + assert(dfsan_get_label(strd[0]) == 0); + assert(dfsan_get_label(strd[3]) == i_label); + free(strd); + + rv = strncmp(str1, str2, sizeof(str1)); + assert(rv < 0); + assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label)); + + rv = strncmp(str1, str2, 3); + assert(rv == 0); + assert(dfsan_get_label(rv) == 0); + + str1[0] = 'S'; + + rv = strncasecmp(str1, str2, sizeof(str1)); + assert(rv < 0); + assert(dfsan_get_label(rv) == dfsan_union(i_label, j_label)); + + rv = strncasecmp(str1, str2, 3); + assert(rv == 0); + assert(dfsan_get_label(rv) == 0); + + char *crv = strchr(str1, 'r'); + assert(crv == &str1[2]); + assert(dfsan_get_label((uintptr_t)crv) == 0); + + crv = strchr(str1, '1'); + assert(crv == &str1[3]); + assert(dfsan_get_label((uintptr_t)crv) == i_label); + + crv = strchr(str1, 'x'); + assert(crv == 0); + assert(dfsan_get_label((uintptr_t)crv) == i_label); + + // With any luck this sequence of calls will cause calloc to return the same + // pointer both times. This is probably the best we can do to test this + // function. + crv = calloc(4096, 1); + assert(dfsan_get_label(crv[0]) == 0); + free(crv); + + crv = calloc(4096, 1); + assert(dfsan_get_label(crv[0]) == 0); + free(crv); + + char buf[16]; + buf[0] = i; + buf[15] = j; + rv = read(fd, buf, sizeof(buf)); + assert(rv == sizeof(buf)); + assert(dfsan_get_label(buf[0]) == 0); + assert(dfsan_get_label(buf[15]) == 0); + + close(fd); + fd = open("/bin/sh", O_RDONLY); + buf[0] = i; + buf[15] = j; + rv = pread(fd, buf, sizeof(buf), 0); + assert(rv == sizeof(buf)); + assert(dfsan_get_label(buf[0]) == 0); + assert(dfsan_get_label(buf[15]) == 0); + + pthread_t pt; + pthread_create(&pt, 0, ptcb, (void *)1); + void *cbrv; + pthread_join(pt, &cbrv); + assert(cbrv == (void *)2); + + dl_iterate_phdr(dlcb, (void *)3); + + return 0; +} diff --git a/lib/dfsan/lit_tests/flags.c b/lib/dfsan/lit_tests/flags.c new file mode 100644 index 0000000000000..5cf970dce90df --- /dev/null +++ b/lib/dfsan/lit_tests/flags.c @@ -0,0 +1,24 @@ +// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && %t 2>&1 | FileCheck %s +// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_unimplemented=0 %t 2>&1 | count 0 +// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_nonzero_labels=1 %t 2>&1 | FileCheck --check-prefix=CHECK-NONZERO %s + +// Tests that flags work correctly. + +#include <sanitizer/dfsan_interface.h> + +int f(int i) { + return i; +} + +int main(void) { + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + // CHECK: WARNING: DataFlowSanitizer: call to uninstrumented function f + // CHECK-NOT: WARNING: DataFlowSanitizer: saw nonzero label + // CHECK-NONZERO: WARNING: DataFlowSanitizer: saw nonzero label + f(i); + + return 0; +} diff --git a/lib/dfsan/lit_tests/fncall.c b/lib/dfsan/lit_tests/fncall.c new file mode 100644 index 0000000000000..15b77bd67902b --- /dev/null +++ b/lib/dfsan/lit_tests/fncall.c @@ -0,0 +1,26 @@ +// RUN: %clang_dfsan -m64 %s -o %t && %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t + +// Tests that labels are propagated through function calls. + +#include <sanitizer/dfsan_interface.h> +#include <assert.h> + +int f(int x) { + int j = 2; + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_set_label(j_label, &j, sizeof(j)); + return x + j; +} + +int main(void) { + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + dfsan_label ij_label = dfsan_get_label(f(i)); + assert(dfsan_has_label(ij_label, i_label)); + assert(dfsan_has_label_with_desc(ij_label, "j")); + + return 0; +} diff --git a/lib/dfsan/lit_tests/lit.cfg b/lib/dfsan/lit_tests/lit.cfg new file mode 100644 index 0000000000000..19bc97690a860 --- /dev/null +++ b/lib/dfsan/lit_tests/lit.cfg @@ -0,0 +1,69 @@ +# -*- Python -*- + +import os + +import lit.util + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if not attr_value: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +# Setup config name. +config.name = 'DataFlowSanitizer' + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +def DisplayNoConfigMessage(): + lit_config.fatal("No site specific configuration available! " + + "Try running your test from the build tree or running " + + "make check-dfsan") + +# Figure out LLVM source root. +llvm_src_root = getattr(config, 'llvm_src_root', None) +if llvm_src_root is None: + # We probably haven't loaded the site-specific configuration: the user + # is likely trying to run a test file directly, and the site configuration + # wasn't created by the build system. + dfsan_site_cfg = lit_config.params.get('dfsan_site_config', None) + if (dfsan_site_cfg) and (os.path.exists(dfsan_site_cfg)): + lit_config.load_config(config, dfsan_site_cfg) + raise SystemExit + + # Try to guess the location of site-specific configuration using llvm-config + # util that can point where the build tree is. + llvm_config = lit.util.which("llvm-config", config.environment["PATH"]) + if not llvm_config: + DisplayNoConfigMessage() + + # Find out the presumed location of generated site config. + llvm_obj_root = lit.util.capture(["llvm-config", "--obj-root"]).strip() + dfsan_site_cfg = os.path.join(llvm_obj_root, "projects", "compiler-rt", + "lib", "dfsan", "lit_tests", "lit.site.cfg") + if (not dfsan_site_cfg) or (not os.path.exists(dfsan_site_cfg)): + DisplayNoConfigMessage() + + lit_config.load_config(config, dfsan_site_cfg) + raise SystemExit + +# Setup default compiler flags used with -fsanitize=dataflow option. +clang_dfsan_cflags = ["-fsanitize=dataflow"] +clang_dfsan_cxxflags = ["--driver-mode=g++ "] + clang_dfsan_cflags +config.substitutions.append( ("%clang_dfsan ", + " ".join([config.clang] + clang_dfsan_cflags) + + " ") ) +config.substitutions.append( ("%clangxx_dfsan ", + " ".join([config.clang] + clang_dfsan_cxxflags) + + " ") ) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +# DataFlowSanitizer tests are currently supported on Linux only. +if config.host_os not in ['Linux']: + config.unsupported = True diff --git a/lib/dfsan/lit_tests/lit.site.cfg.in b/lib/dfsan/lit_tests/lit.site.cfg.in new file mode 100644 index 0000000000000..0cf6d6b5580f8 --- /dev/null +++ b/lib/dfsan/lit_tests/lit.site.cfg.in @@ -0,0 +1,5 @@ +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@DFSAN_SOURCE_DIR@/lit_tests/lit.cfg") diff --git a/lib/dfsan/lit_tests/propagate.c b/lib/dfsan/lit_tests/propagate.c new file mode 100644 index 0000000000000..86d182b8a7fc2 --- /dev/null +++ b/lib/dfsan/lit_tests/propagate.c @@ -0,0 +1,47 @@ +// RUN: %clang_dfsan -m64 %s -o %t && %t +// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %t + +// Tests that labels are propagated through computation and that union labels +// are properly created. + +#include <sanitizer/dfsan_interface.h> +#include <assert.h> + +int main(void) { + assert(dfsan_union(0, 0) == 0); + + int i = 1; + dfsan_label i_label = dfsan_create_label("i", 0); + dfsan_set_label(i_label, &i, sizeof(i)); + + int j = 2; + dfsan_label j_label = dfsan_create_label("j", 0); + dfsan_set_label(j_label, &j, sizeof(j)); + + int k = 3; + dfsan_label k_label = dfsan_create_label("k", 0); + dfsan_set_label(k_label, &k, sizeof(k)); + + int k2 = 4; + dfsan_set_label(k_label, &k2, sizeof(k2)); + + dfsan_label ij_label = dfsan_get_label(i + j); + assert(dfsan_has_label(ij_label, i_label)); + assert(dfsan_has_label(ij_label, j_label)); + assert(!dfsan_has_label(ij_label, k_label)); + // Test uniquing. + assert(dfsan_union(i_label, j_label) == ij_label); + assert(dfsan_union(j_label, i_label) == ij_label); + + dfsan_label ijk_label = dfsan_get_label(i + j + k); + assert(dfsan_has_label(ijk_label, i_label)); + assert(dfsan_has_label(ijk_label, j_label)); + assert(dfsan_has_label(ijk_label, k_label)); + + assert(dfsan_get_label(k + k2) == k_label); + + struct { int i, j; } s = { i, j }; + assert(dfsan_read_label(&s, sizeof(s)) == ij_label); + + return 0; +} |