summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2014-04-01 13:16:30 +0000
committerAlexey Samsonov <samsonov@google.com>2014-04-01 13:16:30 +0000
commitd6535ea4c4d49078a93735b315b8518fb692a592 (patch)
treee114342968d294d188587a94d6dea587a66e3f19
parentf9470a30623dab95050c32e10576d706b13675dd (diff)
[ASan] Optional support for dynamic ASan runtime on Linux.
Based on http://llvm-reviews.chandlerc.com/D3042 by Yuri Gribov! git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@205308 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--CMakeLists.txt2
-rw-r--r--cmake/Modules/AddCompilerRT.cmake6
-rw-r--r--cmake/config-ix.cmake1
-rw-r--r--lib/asan/CMakeLists.txt51
-rw-r--r--lib/asan/asan_internal.h6
-rw-r--r--lib/asan/asan_linux.cc76
-rw-r--r--lib/asan/asan_mac.cc6
-rw-r--r--lib/asan/asan_rtl.cc18
-rw-r--r--lib/asan/asan_win.cc4
-rw-r--r--lib/asan/tests/CMakeLists.txt16
-rw-r--r--test/asan/CMakeLists.txt26
-rw-r--r--test/asan/TestCases/Linux/asan_dlopen_test.cc14
-rw-r--r--test/asan/TestCases/Linux/asan_preload_test-1.cc27
-rw-r--r--test/asan/TestCases/Linux/asan_preload_test-2.cc21
-rw-r--r--test/asan/TestCases/Linux/asan_rt_confict_test-1.cc12
-rw-r--r--test/asan/TestCases/Linux/asan_rt_confict_test-2.cc24
-rw-r--r--test/asan/TestCases/Linux/interface_symbols_linux.c2
-rw-r--r--test/asan/TestCases/sanity_check_pure_c.c2
-rw-r--r--test/asan/Unit/lit.site.cfg.in10
-rw-r--r--test/asan/lit.cfg40
-rw-r--r--test/asan/lit.site.cfg.in2
-rw-r--r--test/lit.common.configured.in2
-rw-r--r--unittests/lit.common.unit.configured.in1
23 files changed, 345 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2d40d97b..6190be404 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -231,6 +231,8 @@ option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
pythonize_bool(COMPILER_RT_DEBUG)
+option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" OFF)
+
#================================
# Setup Compiler Flags
#================================
diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake
index 556ada48a..82947eac4 100644
--- a/cmake/Modules/AddCompilerRT.cmake
+++ b/cmake/Modules/AddCompilerRT.cmake
@@ -45,7 +45,7 @@ endmacro()
# DEFS <compile definitions>)
macro(add_compiler_rt_runtime name arch type)
if(CAN_TARGET_${arch})
- parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
+ parse_arguments(LIB "SOURCES;CFLAGS;DEFS;OUTPUT_NAME" "" ${ARGN})
add_library(${name} ${type} ${LIB_SOURCES})
# Setup compile flags and definitions.
set_target_compile_flags(${name}
@@ -58,6 +58,10 @@ macro(add_compiler_rt_runtime name arch type)
set_target_properties(${name} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
+ if (LIB_OUTPUT_NAME)
+ set_target_properties(${name} PROPERTIES
+ OUTPUT_NAME ${LIB_OUTPUT_NAME})
+ endif()
# Add installation command.
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index d9cc7f0e7..fe194d50d 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -15,6 +15,7 @@ check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
check_cxx_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
+check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)
check_cxx_compiler_flag(/GR COMPILER_RT_HAS_GR_FLAG)
check_cxx_compiler_flag(/GS COMPILER_RT_HAS_GS_FLAG)
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt
index d1c0d801c..88647b841 100644
--- a/lib/asan/CMakeLists.txt
+++ b/lib/asan/CMakeLists.txt
@@ -21,7 +21,6 @@ set(ASAN_SOURCES
asan_new_delete.cc
asan_poisoning.cc
asan_posix.cc
- asan_preinit.cc
asan_report.cc
asan_rtl.cc
asan_stack.cc
@@ -29,6 +28,9 @@ set(ASAN_SOURCES
asan_thread.cc
asan_win.cc)
+set(ASAN_PREINIT_SOURCES
+ asan_preinit.cc)
+
include_directories(..)
if(ANDROID)
@@ -46,6 +48,17 @@ if(ANDROID)
ASAN_LOW_MEMORY=1)
endif()
+set(ASAN_DYNAMIC_DEFINITIONS
+ ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1)
+
+set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
+append_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
+ -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
+
+set(ASAN_DYNAMIC_LIBS stdc++ m c)
+append_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS)
+append_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)
+
if (NOT MSVC)
set(ASAN_ASM_SOURCES asan_asm_instrumentation.S)
set_source_files_properties(${ASAN_ASM_SOURCES} PROPERTIES LANGUAGE C)
@@ -71,6 +84,14 @@ else()
add_compiler_rt_object_library(RTAsan ${arch}
SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_compiler_rt_object_library(RTAsan_preinit ${arch}
+ SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_object_library(RTAsan_dynamic ${arch}
+ SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ endif()
endforeach()
endif()
@@ -103,21 +124,41 @@ elseif(ANDROID)
else()
# Build separate libraries for each target.
foreach(arch ${ASAN_SUPPORTED_ARCH})
- set(ASAN_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTAsan.${arch}>
+ set(ASAN_COMMON_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTInterception.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
if (NOT WIN32)
# We can't build Leak Sanitizer on Windows yet.
- list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+ list(APPEND ASAN_COMMON_RUNTIME_OBJECTS
+ $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
endif()
add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
- SOURCES ${ASAN_RUNTIME_OBJECTS}
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ $<TARGET_OBJECTS:RTAsan.${arch}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
CFLAGS ${ASAN_CFLAGS}
DEFS ${ASAN_COMMON_DEFINITIONS})
add_dependencies(asan clang_rt.asan-${arch})
+
+ if (COMPILER_RT_BUILD_SHARED_ASAN)
+ add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC
+ SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
+ CFLAGS ${ASAN_CFLAGS}
+ DEFS ${ASAN_COMMON_DEFINITIONS})
+ add_dependencies(asan clang_rt.asan-preinit-${arch})
+
+ add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
+ OUTPUT_NAME clang_rt.asan-${arch}
+ SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
+ ${ASAN_COMMON_RUNTIME_OBJECTS}
+ CFLAGS ${ASAN_DYNAMIC_CFLAGS}
+ DEFS ${ASAN_DYNAMIC_DEFINITIONS})
+ target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS})
+ add_dependencies(asan clang_rt.asan-dynamic-${arch})
+ endif()
+
if (UNIX AND NOT ${arch} STREQUAL "i386")
add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra)
add_dependencies(asan clang_rt.asan-${arch}-symbols)
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 4dbcae193..4934d6cd7 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -49,6 +49,10 @@
# define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID)
#endif
+#ifndef ASAN_DYNAMIC
+# define ASAN_DYNAMIC 0
+#endif
+
// All internal functions in asan reside inside the __asan namespace
// to avoid namespace collisions with the user programs.
// Seperate namespace also makes it simpler to distinguish the asan run-time
@@ -69,6 +73,8 @@ void ReplaceSystemMalloc();
// asan_linux.cc / asan_mac.cc / asan_win.cc
void *AsanDoesNotSupportStaticLinkage();
+void AsanCheckDynamicRTPrereqs();
+void AsanCheckIncompatibleRT();
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
void AsanOnSIGSEGV(int, void *siginfo, void *context);
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 5529f56bd..c6085aa7b 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -35,8 +35,11 @@
#if SANITIZER_ANDROID
#include <ucontext.h>
+extern "C" void* _DYNAMIC;
#else
#include <sys/ucontext.h>
+#include <dlfcn.h>
+#include <link.h>
#endif
// x86_64 FreeBSD 9.2 and older define 64-bit register names in both 64-bit
@@ -50,7 +53,17 @@
# endif
#endif
-extern "C" void* _DYNAMIC;
+typedef enum {
+ ASAN_RT_VERSION_UNDEFINED = 0,
+ ASAN_RT_VERSION_DYNAMIC,
+ ASAN_RT_VERSION_STATIC,
+} asan_rt_version_t;
+
+// FIXME: perhaps also store abi version here?
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+asan_rt_version_t __asan_rt_version;
+}
namespace __asan {
@@ -63,6 +76,67 @@ void *AsanDoesNotSupportStaticLinkage() {
return &_DYNAMIC; // defined in link.h
}
+static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ // Continue until the first dynamic library is found
+ if (!info->dlpi_name || info->dlpi_name[0] == 0)
+ return 0;
+
+ *(const char **)data = info->dlpi_name;
+ return 1;
+}
+
+static bool IsDynamicRTName(const char *libname) {
+ return internal_strstr(libname, "libclang_rt.asan") ||
+ internal_strstr(libname, "libasan.so");
+}
+
+void AsanCheckDynamicRTPrereqs() {
+ // FIXME: can we do something like this for Android?
+#if !SANITIZER_ANDROID
+ // Ensure that dynamic RT is the first DSO in the list
+ const char *first_dso_name = 0;
+ dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
+ if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
+ Report("ASan runtime does not come first in initial library list; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
+ Die();
+ }
+#endif
+}
+
+void AsanCheckIncompatibleRT() {
+#if !SANITIZER_ANDROID
+ if (ASAN_DYNAMIC) {
+ if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
+ __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
+ } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ } else {
+ // Ensure that dynamic runtime is not present. We should detect it
+ // as early as possible, otherwise ASan interceptors could bind to
+ // the functions in dynamic ASan runtime instead of the functions in
+ // system libraries, causing crashes later in ASan initialization.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ char filename[128];
+ while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
+ if (IsDynamicRTName(filename)) {
+ Report("Your application is linked against "
+ "incompatible ASan runtimes.\n");
+ Die();
+ }
+ }
+
+ CHECK_NE(__asan_rt_version, ASAN_RT_VERSION_DYNAMIC);
+ __asan_rt_version = ASAN_RT_VERSION_STATIC;
+ }
+#endif
+}
+
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 0428a1845..9f2fabd69 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -199,6 +199,12 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckDynamicRTPrereqs() {}
+
+// No-op. Mac does not support static linkage anyway.
+void AsanCheckIncompatibleRT() {}
+
bool AsanInterceptsSignal(int signum) {
return (signum == SIGSEGV || signum == SIGBUS) &&
common_flags()->handle_segv;
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 631b5c955..2d93a8897 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -637,6 +637,23 @@ void AsanInitFromRtl() {
AsanInitInternal();
}
+#if ASAN_DYNAMIC
+// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
+// (and thus normal initializer from .preinit_array haven't run).
+
+class AsanInitializer {
+public: // NOLINT
+ AsanInitializer() {
+ AsanCheckIncompatibleRT();
+ AsanCheckDynamicRTPrereqs();
+ if (!asan_inited)
+ __asan_init();
+ }
+};
+
+static AsanInitializer asan_initializer;
+#endif // ASAN_DYNAMIC
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
@@ -688,6 +705,7 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
// Initialize as requested from instrumented application code.
// We use this call as a trigger to wake up ASan from deactivated state.
void __asan_init() {
+ AsanCheckIncompatibleRT();
AsanActivate();
AsanInitInternal();
}
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 54fec2b14..da26e989a 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -70,6 +70,10 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); }
+
+void AsanCheckIncompatibleRT() {}
+
void AsanPlatformThreadInit() {
// Nothing here for now.
}
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index e01d6ea8a..e85cfaf88 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -66,10 +66,16 @@ if(NOT ANDROID)
list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address)
endif()
+set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS
+ ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}
+ -shared-libasan)
+
set(ASAN_UNITTEST_NOINST_LINKFLAGS
${ASAN_UNITTEST_COMMON_LINKFLAGS} -lm)
append_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS)
append_if(COMPILER_RT_HAS_LIBPTHREAD -lpthread ASAN_UNITTEST_NOINST_LINKFLAGS)
+append_if(COMPILER_RT_HAS_LIBPTHREAD -lpthread
+ ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS)
# Compile source for the given architecture, using compiler
# options in ${ARGN}, and add it to the object list.
@@ -154,6 +160,11 @@ macro(add_asan_tests_for_arch arch)
add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch}
OBJECTS ${ASAN_INST_TEST_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanUnitTests "Asan-${arch}-Dynamic-Test" ${arch}
+ OBJECTS ${ASAN_INST_TEST_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
# Add static ASan runtime that will be linked with uninstrumented tests.
set(ASAN_TEST_RUNTIME RTAsanTest.${arch})
@@ -194,6 +205,11 @@ macro(add_asan_tests_for_arch arch)
add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch}
OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ add_asan_test(AsanBenchmarks "Asan-${arch}-Dynamic-Benchmark" ${arch}
+ OBJECTS ${ASAN_BENCHMARKS_OBJECTS}
+ LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS})
+ endif()
endmacro()
if(COMPILER_RT_CAN_EXECUTE_TESTS)
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt
index 954fc7065..0dd6f816a 100644
--- a/test/asan/CMakeLists.txt
+++ b/test/asan/CMakeLists.txt
@@ -21,29 +21,47 @@ if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64)
set(ASAN_TEST_CONFIG_SUFFIX "64")
set(ASAN_TEST_BITS "64")
set(ASAN_TEST_TARGET_CFLAGS ${TARGET_64_BIT_CFLAGS})
+ set(ASAN_TEST_DYNAMIC False)
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
)
list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ set(ASAN_TEST_CONFIG_SUFFIX "64-Dynamic")
+ set(ASAN_TEST_DYNAMIC True)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic/lit.site.cfg)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic)
+ endif()
endif()
if(CAN_TARGET_i386)
set(ASAN_TEST_CONFIG_SUFFIX "32")
set(ASAN_TEST_BITS "32")
set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
+ set(ASAN_TEST_DYNAMIC False)
+ set(ASAN_TEST_TARGET_ARCH "i386")
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
)
list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
+ set(ASAN_TEST_DYNAMIC True)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+ endif()
endif()
if(COMPILER_RT_INCLUDE_TESTS)
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
endif()
set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
diff --git a/test/asan/TestCases/Linux/asan_dlopen_test.cc b/test/asan/TestCases/Linux/asan_dlopen_test.cc
new file mode 100644
index 000000000..83ce4f83b
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_dlopen_test.cc
@@ -0,0 +1,14 @@
+// Test that dlopen of dynamic runtime is prohibited.
+//
+// RUN: %clangxx %s -DRT=\"%shared_libasan\" -o %t -ldl
+// RUN: not %t 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+
+#include <dlfcn.h>
+
+int main(int argc, char **argv) {
+ dlopen(RT, RTLD_LAZY);
+ return 0;
+}
+
+// CHECK: ASan runtime does not come first in initial library list
diff --git a/test/asan/TestCases/Linux/asan_preload_test-1.cc b/test/asan/TestCases/Linux/asan_preload_test-1.cc
new file mode 100644
index 000000000..f6eff8ee1
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_preload_test-1.cc
@@ -0,0 +1,27 @@
+// Test that non-sanitized executables work with sanitized shared libs
+// and preloaded runtime.
+//
+// RUN: %clangxx -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: %clangxx %s %t.so -o %t
+//
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: LD_PRELOAD=%shared_libasan not %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+#if BUILD_SO
+char dummy;
+void do_access(const void *p) {
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ dummy = ((const char *)p)[1];
+}
+#else
+#include <stdlib.h>
+extern void do_access(const void *p);
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ free(p);
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Linux/asan_preload_test-2.cc b/test/asan/TestCases/Linux/asan_preload_test-2.cc
new file mode 100644
index 000000000..a0f88ce93
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_preload_test-2.cc
@@ -0,0 +1,21 @@
+// Test that preloaded runtime works with unsanitized executables.
+//
+// RUN: %clangxx %s -o %t
+// RUN: LD_PRELOAD=%shared_libasan not %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+#include <stdlib.h>
+
+extern "C" void *memset(void *p, int val, size_t n);
+
+void do_access(void *p) {
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ memset(p, 0, 2);
+}
+
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc
new file mode 100644
index 000000000..a66aaf2a8
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc
@@ -0,0 +1,12 @@
+// Test that preloading dynamic runtime to statically sanitized
+// executable is prohibited.
+//
+// RUN: %clangxx_asan_static %s -o %t
+// RUN: LD_PRELOAD=%shared_libasan not %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+#include <stdlib.h>
+int main(int argc, char **argv) { return 0; }
+
+// CHECK: Your application is linked against incompatible ASan runtimes
diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc
new file mode 100644
index 000000000..3898e7bb1
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc
@@ -0,0 +1,24 @@
+// Test that mixed static/dynamic sanitization of program objects
+// is prohibited.
+//
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: %clangxx_asan_static %s %t.so -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+#if BUILD_SO
+char dummy;
+void do_access(const void *p) { dummy = ((const char *)p)[1]; }
+#else
+#include <stdlib.h>
+extern void do_access(const void *p);
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ free(p);
+ return 0;
+}
+#endif
+
+// CHECK: Your application is linked against incompatible ASan runtimes
diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c
index f67a12476..4764ef7f0 100644
--- a/test/asan/TestCases/Linux/interface_symbols_linux.c
+++ b/test/asan/TestCases/Linux/interface_symbols_linux.c
@@ -31,6 +31,6 @@
// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
// in "initialized data section".
-// REQUIRES: x86_64-supported-target,i386-supported-target
+// REQUIRES: x86_64-supported-target,i386-supported-target,asan-static-runtime
int main() { return 0; }
diff --git a/test/asan/TestCases/sanity_check_pure_c.c b/test/asan/TestCases/sanity_check_pure_c.c
index df150675b..6065532a5 100644
--- a/test/asan/TestCases/sanity_check_pure_c.c
+++ b/test/asan/TestCases/sanity_check_pure_c.c
@@ -3,7 +3,7 @@
// RUN: not %t 2>&1 | FileCheck %s
// Sanity checking a test in pure C with -pie.
-// RUN: %clang_asan -O2 %s -pie -o %t
+// RUN: %clang_asan -O2 %s -pie -fPIE -o %t
// RUN: not %t 2>&1 | FileCheck %s
#include <stdlib.h>
diff --git a/test/asan/Unit/lit.site.cfg.in b/test/asan/Unit/lit.site.cfg.in
index 96cfc386a..46eea1ff9 100644
--- a/test/asan/Unit/lit.site.cfg.in
+++ b/test/asan/Unit/lit.site.cfg.in
@@ -1,9 +1,16 @@
## Autogenerated by LLVM/Clang configuration.
# Do not edit!
+import os
+
# Load common config for all compiler-rt unit tests.
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+def push_ld_library_path(config, new_path):
+ new_ld_library_path = os.path.pathsep.join(
+ (new_path, config.environment['LD_LIBRARY_PATH']))
+ config.environment['LD_LIBRARY_PATH'] = new_ld_library_path
+
# Setup config name.
config.name = 'AddressSanitizer-Unit'
@@ -13,6 +20,9 @@ config.name = 'AddressSanitizer-Unit'
config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/asan/tests"
config.test_source_root = config.test_exec_root
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_ld_library_path(config, config.compiler_rt_libdir)
+
# Enable leak detection in ASan unit tests on x86_64-linux.
if config.host_os == 'Linux' and config.host_arch == 'x86_64':
config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index f24e68037..7f47b43ed 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -11,6 +11,11 @@ def get_required_attr(config, attr_name):
"to lit.site.cfg " % attr_name)
return attr_value
+def push_ld_library_path(config, new_path):
+ new_ld_library_path = os.path.pathsep.join(
+ (new_path, config.environment['LD_LIBRARY_PATH']))
+ config.environment['LD_LIBRARY_PATH'] = new_ld_library_path
+
# Setup config name.
config.name = 'AddressSanitizer' + config.name_suffix
@@ -27,12 +32,21 @@ else:
# FIXME: Review the set of required flags and check if it can be reduced.
target_cflags = [get_required_attr(config, "target_cflags")] + extra_linkflags
target_cxxflags = config.cxx_mode_flags + target_cflags
-clang_asan_cflags = ["-fsanitize=address",
- "-mno-omit-leaf-frame-pointer",
- "-fno-omit-frame-pointer",
- "-fno-optimize-sibling-calls",
- "-g"] + target_cflags
-clang_asan_cxxflags = config.cxx_mode_flags + clang_asan_cflags
+clang_asan_static_cflags = ["-fsanitize=address",
+ "-mno-omit-leaf-frame-pointer",
+ "-fno-omit-frame-pointer",
+ "-fno-optimize-sibling-calls",
+ "-g"] + target_cflags
+clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags
+
+if config.asan_dynamic:
+ clang_asan_cflags = clang_asan_static_cflags + ['-shared-libasan']
+ clang_asan_cxxflags = clang_asan_static_cxxflags + ['-shared-libasan']
+ config.available_features.add("asan-dynamic-runtime")
+else:
+ clang_asan_cflags = clang_asan_static_cflags
+ clang_asan_cxxflags = clang_asan_static_cxxflags
+ config.available_features.add("asan-static-runtime")
asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir")
if config.android == "TRUE":
@@ -49,6 +63,10 @@ config.substitutions.append( ("%clang ", build_invocation(target_cflags)) )
config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) )
config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) )
config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) )
+config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch))
+if config.asan_dynamic:
+ config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) )
+ config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) )
# FIXME: De-hardcode this path.
asan_source_dir = os.path.join(
@@ -76,14 +94,14 @@ config.available_features.add("asan-" + config.bits + "-bits")
if config.host_os == 'Linux' and config.bits == '64':
config.environment['ASAN_OPTIONS'] = 'detect_leaks=1'
-# GCC-ASan uses dynamic runtime by default, so we have to set LD_LIBRARY_PATH
-# to pick it up properly.
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_ld_library_path(config, config.compiler_rt_libdir)
+
+# GCC-ASan uses dynamic runtime by default.
if config.compiler_id == 'GNU':
gcc_dir = os.path.dirname(config.clang)
libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
- new_ld_library_path = os.path.pathsep.join(
- (libasan_dir, config.environment['LD_LIBRARY_PATH']))
- config.environment['LD_LIBRARY_PATH'] = new_ld_library_path
+ push_ld_library_path(config, libasan_dir)
# Default test suffixes.
config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in
index 48ea81252..76e0c5542 100644
--- a/test/asan/lit.site.cfg.in
+++ b/test/asan/lit.site.cfg.in
@@ -9,6 +9,8 @@ config.clang = "@ASAN_TEST_TARGET_CC@"
config.llvm_tools_dir = "@ASAN_TEST_LLVM_TOOLS_DIR@"
config.bits = "@ASAN_TEST_BITS@"
config.android = "@CAN_TARGET_arm_android@"
+config.asan_dynamic = @ASAN_TEST_DYNAMIC@
+config.target_arch = "@ASAN_TEST_TARGET_ARCH@"
# 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/lit.common.configured.in b/test/lit.common.configured.in
index f33be90e7..7a9dd29b2 100644
--- a/test/lit.common.configured.in
+++ b/test/lit.common.configured.in
@@ -9,6 +9,7 @@ def set_default(attr, value):
# Generic config options for all compiler-rt lit tests.
set_default("target_triple", "@TARGET_TRIPLE@")
set_default("host_arch", "@HOST_ARCH@")
+set_default("target_arch", "@HOST_ARCH@")
set_default("host_os", "@HOST_OS@")
set_default("llvm_build_mode", "@LLVM_BUILD_MODE@")
set_default("llvm_src_root", "@LLVM_SOURCE_DIR@")
@@ -20,6 +21,7 @@ set_default("compiler_id", "@COMPILER_RT_TEST_COMPILER_ID@")
set_default("compiler_rt_arch", "@COMPILER_RT_SUPPORTED_ARCH@")
set_default("python_executable", "@PYTHON_EXECUTABLE@")
set_default("compiler_rt_debug", @COMPILER_RT_DEBUG_PYBOOL@)
+set_default("compiler_rt_libdir", "@COMPILER_RT_LIBRARY_OUTPUT_DIR@")
# LLVM tools dir can be passed in lit parameters, so try to
# apply substitution.
diff --git a/unittests/lit.common.unit.configured.in b/unittests/lit.common.unit.configured.in
index fe827c638..ab5c253c7 100644
--- a/unittests/lit.common.unit.configured.in
+++ b/unittests/lit.common.unit.configured.in
@@ -7,6 +7,7 @@ config.llvm_src_root = "@LLVM_SOURCE_DIR@"
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@"
+config.compiler_rt_libdir = "@COMPILER_RT_LIBRARY_OUTPUT_DIR@"
config.llvm_build_mode = "@LLVM_BUILD_MODE@"
config.host_arch = "@HOST_ARCH@"
config.host_os = "@HOST_OS@"