diff options
-rw-r--r-- | include/CMakeLists.txt | 1 | ||||
-rw-r--r-- | include/sanitizer/dfsan_interface.h | 80 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Makefile.mk | 1 | ||||
-rw-r--r-- | lib/dfsan/CMakeLists.txt | 29 | ||||
-rw-r--r-- | lib/dfsan/Makefile.mk | 23 | ||||
-rw-r--r-- | lib/dfsan/dfsan.cc | 221 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/CMakeLists.txt | 23 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/basic.c | 17 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/fncall.c | 25 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/lit.cfg | 66 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/lit.site.cfg.in | 17 | ||||
-rw-r--r-- | lib/dfsan/lit_tests/propagate.c | 33 | ||||
-rw-r--r-- | make/platform/clang_linux.mk | 5 |
14 files changed, 541 insertions, 1 deletions
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 3b39dfa9e..67e1327a3 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,6 +1,7 @@ set(SANITIZER_HEADERS sanitizer/asan_interface.h sanitizer/common_interface_defs.h + sanitizer/dfsan_interface.h sanitizer/linux_syscall_hooks.h sanitizer/lsan_interface.h sanitizer/msan_interface.h) diff --git a/include/sanitizer/dfsan_interface.h b/include/sanitizer/dfsan_interface.h new file mode 100644 index 000000000..a6fc26ee7 --- /dev/null +++ b/include/sanitizer/dfsan_interface.h @@ -0,0 +1,80 @@ +//===-- dfsan_interface.h -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of DataFlowSanitizer. +// +// Public interface header. +//===----------------------------------------------------------------------===// +#ifndef DFSAN_INTERFACE_H +#define DFSAN_INTERFACE_H + +#include <stddef.h> +#include <stdint.h> +#include <sanitizer/common_interface_defs.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint16_t dfsan_label; + +/// Stores information associated with a specific label identifier. A label +/// may be a base label created using dfsan_create_label, with associated +/// text description and user data, or an automatically created union label, +/// which represents the union of two label identifiers (which may themselves +/// be base or union labels). +struct dfsan_label_info { + // Fields for union labels, set to 0 for base labels. + dfsan_label l1; + dfsan_label l2; + + // Fields for base labels. + const char *desc; + void *userdata; +}; + +/// Creates and returns a base label with the given description and user data. +dfsan_label dfsan_create_label(const char *desc, void *userdata); + +/// Sets the label for each address in [addr,addr+size) to \c label. +void dfsan_set_label(dfsan_label label, void *addr, size_t size); + +/// Sets the label for each address in [addr,addr+size) to the union of the +/// current label for that address and \c label. +void dfsan_add_label(dfsan_label label, void *addr, size_t size); + +/// Retrieves the label associated with the given data. +/// +/// The type of 'data' is arbitrary. The function accepts a value of any type, +/// which can be truncated or extended (implicitly or explicitly) as necessary. +/// The truncation/extension operations will preserve the label of the original +/// value. +dfsan_label dfsan_get_label(long data); + +/// Retrieves a pointer to the dfsan_label_info struct for the given label. +const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label); + +/// Returns whether the given label label contains the label elem. +int dfsan_has_label(dfsan_label label, dfsan_label elem); + +/// If the given label label contains a label with the description desc, returns +/// that label, else returns 0. +dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc); + +#ifdef __cplusplus +} // extern "C" + +template <typename T> +void dfsan_set_label(dfsan_label label, T &data) { + dfsan_set_label(label, (void *)&data, sizeof(T)); +} + +#endif + +#endif // DFSAN_INTERFACE_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a3bc3724f..bc3a2574d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -17,6 +17,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND NOT ANDROID) add_subdirectory(tsan) add_subdirectory(msan) add_subdirectory(msandr) + add_subdirectory(dfsan) endif() # The top-level lib directory contains a large amount of C code which provides diff --git a/lib/Makefile.mk b/lib/Makefile.mk index 8054c35aa..f9d7800cc 100644 --- a/lib/Makefile.mk +++ b/lib/Makefile.mk @@ -22,6 +22,7 @@ SubDirs += tsan SubDirs += msan SubDirs += ubsan SubDirs += lsan +SubDirs += dfsan # Define the variables for this specific directory. Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt new file mode 100644 index 000000000..8ac9532d9 --- /dev/null +++ b/lib/dfsan/CMakeLists.txt @@ -0,0 +1,29 @@ +include_directories(..) + +# Runtime library sources and build flags. +set(DFSAN_RTL_SOURCES + dfsan.cc + ) +set(DFSAN_RTL_CFLAGS + ${SANITIZER_COMMON_CFLAGS} + # Prevent clang from generating libc calls. + -ffreestanding) + +# Static runtime library. +set(DFSAN_RUNTIME_LIBRARIES) +set(arch "x86_64") +if(CAN_TARGET_${arch}) + add_compiler_rt_static_runtime(clang_rt.dfsan-${arch} ${arch} + SOURCES ${DFSAN_RTL_SOURCES} + $<TARGET_OBJECTS:RTInterception.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + CFLAGS ${DFSAN_RTL_CFLAGS} -fPIE) + add_compiler_rt_static_runtime(clang_rt.dfsan-libc-${arch} ${arch} + SOURCES ${DFSAN_RTL_SOURCES} + $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> + CFLAGS ${DFSAN_RTL_CFLAGS} -fPIC -DDFSAN_NOLIBC) + list(APPEND DFSAN_RUNTIME_LIBRARIES clang_rt.dfsan-${arch}) +endif() + +add_subdirectory(lit_tests) diff --git a/lib/dfsan/Makefile.mk b/lib/dfsan/Makefile.mk new file mode 100644 index 000000000..4aeaac42d --- /dev/null +++ b/lib/dfsan/Makefile.mk @@ -0,0 +1,23 @@ +#===- lib/dfsan/Makefile.mk --------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := dfsan +SubDirs := + +Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file))) +ObjNames := $(Sources:%.cc=%.o) + +Implementation := Generic + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard $(Dir)/*.h) +Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h) + +# Define a convenience variable for all the dfsan functions. +DfsanFunctions := $(Sources:%.cc=%) diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc new file mode 100644 index 000000000..a0db6ebd6 --- /dev/null +++ b/lib/dfsan/dfsan.cc @@ -0,0 +1,221 @@ +//===-- dfsan.cc ----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of DataFlowSanitizer. +// +// DataFlowSanitizer runtime. This file defines the public interface to +// DataFlowSanitizer as well as the definition of certain runtime functions +// called automatically by the compiler (specifically the instrumentation pass +// in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp). +// +// The public interface is defined in include/sanitizer/dfsan_interface.h whose +// functions are prefixed dfsan_ while the compiler interface functions are +// prefixed __dfsan_. +//===----------------------------------------------------------------------===// + +#include "sanitizer/dfsan_interface.h" +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" + +typedef atomic_uint16_t atomic_dfsan_label; +static const dfsan_label kInitializingLabel = -1; + +static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8); + +static atomic_dfsan_label __dfsan_last_label; +static dfsan_label_info __dfsan_label_info[kNumLabels]; + +SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; +SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; + +// On Linux/x86_64, memory is laid out as follows: +// +// +--------------------+ 0x800000000000 (top of memory) +// | application memory | +// +--------------------+ 0x700000008000 (kAppAddr) +// | | +// | unused | +// | | +// +--------------------+ 0x200200000000 (kUnusedAddr) +// | union table | +// +--------------------+ 0x200000000000 (kUnionTableAddr) +// | shadow memory | +// +--------------------+ 0x000000010000 (kShadowAddr) +// | reserved by kernel | +// +--------------------+ 0x000000000000 +// +// To derive a shadow memory address from an application memory address, +// bits 44-46 are cleared to bring the address into the range +// [0x000000008000,0x100000000000). Then the address is shifted left by 1 to +// account for the double byte representation of shadow labels and move the +// address into the shadow memory range. See the function shadow_for below. + +typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels]; + +static const uptr kShadowAddr = 0x10000; +static const uptr kUnionTableAddr = 0x200000000000; +static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); +static const uptr kAppAddr = 0x700000008000; + +static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { + return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2]; +} + +static dfsan_label *shadow_for(void *ptr) { + return (dfsan_label *) ((((uintptr_t) ptr) & ~0x700000000000) << 1); +} + +// Resolves the union of two unequal labels. Nonequality is a precondition for +// this function (the instrumentation pass inlines the equality test). +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) { + DCHECK_NE(l1, l2); + + if (l1 == 0) + return l2; + if (l2 == 0) + return l1; + + if (l1 > l2) + Swap(l1, l2); + + atomic_dfsan_label *table_ent = union_table(l1, l2); + // We need to deal with the case where two threads concurrently request + // a union of the same pair of labels. If the table entry is uninitialized, + // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel + // (i.e. -1) to mark that we are initializing it. + dfsan_label label = 0; + if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel, + memory_order_acquire)) { + // Check whether l2 subsumes l1. We don't need to check whether l1 + // subsumes l2 because we are guaranteed here that l1 < l2, and (at least + // in the cases we are interested in) a label may only subsume labels + // created earlier (i.e. with a lower numerical value). + if (__dfsan_label_info[l2].l1 == l1 || + __dfsan_label_info[l2].l2 == l1) { + label = l2; + } else { + label = + atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; + CHECK_NE(label, kInitializingLabel); + __dfsan_label_info[label].l1 = l1; + __dfsan_label_info[label].l2 = l2; + } + atomic_store(table_ent, label, memory_order_release); + } else if (label == kInitializingLabel) { + // Another thread is initializing the entry. Wait until it is finished. + do { + internal_sched_yield(); + label = atomic_load(table_ent, memory_order_acquire); + } while (label == kInitializingLabel); + } + return label; +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +dfsan_label __dfsan_union_load(dfsan_label *ls, size_t n) { + dfsan_label label = ls[0]; + for (size_t i = 1; i != n; ++i) { + dfsan_label next_label = ls[i]; + if (label != next_label) + label = __dfsan_union(label, next_label); + } + return label; +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void *__dfsan_memcpy(void *dest, const void *src, size_t n) { + dfsan_label *sdest = shadow_for(dest), *ssrc = shadow_for((void *)src); + internal_memcpy((void *)sdest, (void *)ssrc, n * sizeof(dfsan_label)); + return internal_memcpy(dest, src, n); +} + +SANITIZER_INTERFACE_ATTRIBUTE +dfsan_label dfsan_create_label(const char *desc, void *userdata) { + dfsan_label label = + atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; + CHECK_NE(label, kInitializingLabel); + __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0; + __dfsan_label_info[label].desc = desc; + __dfsan_label_info[label].userdata = userdata; + __dfsan_retval_tls = 0; // Ensures return value is unlabelled in the caller. + return label; +} + +SANITIZER_INTERFACE_ATTRIBUTE +void dfsan_set_label(dfsan_label label, void *addr, size_t size) { + for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) + *labelp = label; +} + +SANITIZER_INTERFACE_ATTRIBUTE +void dfsan_add_label(dfsan_label label, void *addr, size_t size) { + for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) + if (*labelp != label) + *labelp = __dfsan_union(*labelp, label); +} + +SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_get_label(long data) { + // The label for 'data' is implicitly passed by the instrumentation pass in + // the first element of __dfsan_arg_tls. So we can just return it. + __dfsan_retval_tls = 0; // Ensures return value is unlabelled in the caller. + return __dfsan_arg_tls[0]; +} + +SANITIZER_INTERFACE_ATTRIBUTE +const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { + __dfsan_retval_tls = 0; // Ensures return value is unlabelled in the caller. + return &__dfsan_label_info[label]; +} + +int dfsan_has_label(dfsan_label label, dfsan_label elem) { + __dfsan_retval_tls = 0; // Ensures return value is unlabelled in the caller. + if (label == elem) + return true; + const dfsan_label_info *info = dfsan_get_label_info(label); + if (info->l1 != 0) { + return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem); + } else { + return false; + } +} + +dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc) { + __dfsan_retval_tls = 0; // Ensures return value is unlabelled in the caller. + const dfsan_label_info *info = dfsan_get_label_info(label); + if (info->l1 != 0) { + return dfsan_has_label_with_desc(info->l1, desc) || + dfsan_has_label_with_desc(info->l2, desc); + } else { + return internal_strcmp(desc, info->desc) == 0; + } +} + +#ifdef DFSAN_NOLIBC +extern "C" void dfsan_init() { +#else +static void dfsan_init(int argc, char **argv, char **envp) { +#endif + MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr); + + // Protect the region of memory we don't use, to preserve the one-to-one + // mapping from application to shadow memory. But if ASLR is disabled, Linux + // will load our executable in the middle of our unused region. This mostly + // works so long as the program doesn't use too much memory. We support this + // case by disabling memory protection when ASLR is disabled. + uptr init_addr = (uptr)&dfsan_init; + if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr)) + Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr); +} + +#ifndef DFSAN_NOLIBC +__attribute__((section(".preinit_array"), used)) +static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; +#endif diff --git a/lib/dfsan/lit_tests/CMakeLists.txt b/lib/dfsan/lit_tests/CMakeLists.txt new file mode 100644 index 000000000..7b800fe1a --- /dev/null +++ b/lib/dfsan/lit_tests/CMakeLists.txt @@ -0,0 +1,23 @@ +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}) + 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/basic.c b/lib/dfsan/lit_tests/basic.c new file mode 100644 index 000000000..db1acb712 --- /dev/null +++ b/lib/dfsan/lit_tests/basic.c @@ -0,0 +1,17 @@ +// RUN: %clang_dfsan -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); + + return 0; +} diff --git a/lib/dfsan/lit_tests/fncall.c b/lib/dfsan/lit_tests/fncall.c new file mode 100644 index 000000000..7d4706f70 --- /dev/null +++ b/lib/dfsan/lit_tests/fncall.c @@ -0,0 +1,25 @@ +// RUN: %clang_dfsan -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 000000000..ce39f4a50 --- /dev/null +++ b/lib/dfsan/lit_tests/lit.cfg @@ -0,0 +1,66 @@ +# -*- Python -*- + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if not attr_value: + lit.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.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.params.get('dfsan_site_config', None) + if (dfsan_site_cfg) and (os.path.exists(dfsan_site_cfg)): + lit.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.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 = ["-ccc-cxx "] + 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 000000000..7586c149a --- /dev/null +++ b/lib/dfsan/lit_tests/lit.site.cfg.in @@ -0,0 +1,17 @@ +config.target_triple = "@TARGET_TRIPLE@" +config.host_os = "@HOST_OS@" +config.llvm_src_root = "@LLVM_SOURCE_DIR@" +config.llvm_obj_root = "@LLVM_BINARY_DIR@" +config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" +config.clang = "@LLVM_BINARY_DIR@/bin/clang" + +# LLVM tools dir can be passed in lit parameters, so try to +# apply substitution. +try: + config.llvm_tools_dir = config.llvm_tools_dir % lit.params +except KeyError,e: + key, = e.args + lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) + +# Let the main config do the real work. +lit.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 000000000..8cc67b812 --- /dev/null +++ b/lib/dfsan/lit_tests/propagate.c @@ -0,0 +1,33 @@ +// RUN: %clang_dfsan -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) { + 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)); + + 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)); + + 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)); + + return 0; +} diff --git a/make/platform/clang_linux.mk b/make/platform/clang_linux.mk index b16e79444..f9c758808 100644 --- a/make/platform/clang_linux.mk +++ b/make/platform/clang_linux.mk @@ -61,7 +61,7 @@ endif # Build runtime libraries for x86_64. ifeq ($(call contains,$(SupportedArches),x86_64),true) Configs += full-x86_64 profile-x86_64 san-x86_64 asan-x86_64 tsan-x86_64 \ - msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64 + msan-x86_64 ubsan-x86_64 ubsan_cxx-x86_64 dfsan-x86_64 Arch.full-x86_64 := x86_64 Arch.profile-x86_64 := x86_64 Arch.san-x86_64 := x86_64 @@ -70,6 +70,7 @@ Arch.tsan-x86_64 := x86_64 Arch.msan-x86_64 := x86_64 Arch.ubsan-x86_64 := x86_64 Arch.ubsan_cxx-x86_64 := x86_64 +Arch.dfsan-x86_64 := x86_64 endif ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),) @@ -101,6 +102,7 @@ CFLAGS.ubsan-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.ubsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) -fno-rtti CFLAGS.ubsan_cxx-i386 := $(CFLAGS) -m32 $(SANITIZER_CFLAGS) CFLAGS.ubsan_cxx-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) +CFLAGS.dfsan-x86_64 := $(CFLAGS) -m64 $(SANITIZER_CFLAGS) SHARED_LIBRARY.asan-arm-android := 1 ANDROID_COMMON_FLAGS := -target arm-linux-androideabi \ @@ -137,6 +139,7 @@ FUNCTIONS.ubsan-i386 := $(UbsanFunctions) FUNCTIONS.ubsan-x86_64 := $(UbsanFunctions) FUNCTIONS.ubsan_cxx-i386 := $(UbsanCXXFunctions) FUNCTIONS.ubsan_cxx-x86_64 := $(UbsanCXXFunctions) +FUNCTIONS.dfsan-x86_64 := $(DfsanFunctions) $(SanitizerCommonFunctions) # Always use optimized variants. OPTIMIZED := 1 |