Index: lib/interception/CMakeLists.txt =================================================================== --- lib/interception/CMakeLists.txt +++ lib/interception/CMakeLists.txt @@ -17,3 +17,7 @@ ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} SOURCES ${INTERCEPTION_SOURCES} CFLAGS ${INTERCEPTION_CFLAGS}) + +if(COMPILER_RT_INCLUDE_TESTS) + add_subdirectory(tests) +endif() Index: lib/interception/interception_win.cc =================================================================== --- lib/interception/interception_win.cc +++ lib/interception/interception_win.cc @@ -341,7 +341,7 @@ } static void **InterestingDLLsAvailable() { - const char *InterestingDLLs[] = { + static const char *InterestingDLLs[] = { "kernel32.dll", "msvcr110.dll", // VS2012 "msvcr120.dll", // VS2013 Index: lib/interception/tests/CMakeLists.txt =================================================================== --- /dev/null +++ lib/interception/tests/CMakeLists.txt @@ -0,0 +1,154 @@ +include(CompilerRTCompile) + +clang_compiler_add_cxx_check() + +filter_available_targets(INTERCEPTION_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el) + +set(INTERCEPTION_UNITTESTS + interception_basic_test.cc + interception_linux_test.cc + interception_test_main.cc + interception_win_test.cc +) + +set(INTERCEPTION_TEST_HEADERS) + +set(INTERCEPTION_TEST_CFLAGS_COMMON + ${COMPILER_RT_UNITTEST_CFLAGS} + ${COMPILER_RT_GTEST_CFLAGS} + -I${COMPILER_RT_SOURCE_DIR}/include + -I${COMPILER_RT_SOURCE_DIR}/lib + -I${COMPILER_RT_SOURCE_DIR}/lib/interception + -fno-rtti + -O2 + -Werror=sign-compare + -Wno-non-virtual-dtor) + +# -gline-tables-only must be enough for these tests, so use it if possible. +if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang") + list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gline-tables-only) +else() + list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -g) +endif() +if(MSVC) + list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gcodeview) +endif() +list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -g) + +if(NOT MSVC) + list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON --driver-mode=g++) +endif() + +if(ANDROID) + list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -pie) +endif() + +set(INTERCEPTION_TEST_LINK_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log INTERCEPTION_TEST_LINK_LIBS) +# NDK r10 requires -latomic almost always. +append_list_if(ANDROID atomic INTERCEPTION_TEST_LINK_LIBS) + +append_list_if(COMPILER_RT_HAS_LIBDL -ldl INTERCEPTION_TEST_LINK_FLAGS_COMMON) +append_list_if(COMPILER_RT_HAS_LIBRT -lrt INTERCEPTION_TEST_LINK_FLAGS_COMMON) +append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread INTERCEPTION_TEST_LINK_FLAGS_COMMON) +# x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also, +# 'libm' shall be specified explicitly to build i386 tests. +if(CMAKE_SYSTEM MATCHES "FreeBSD-9.2-RELEASE") + list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON "-lc++ -lm") +endif() + +include_directories(..) +include_directories(../..) + +# Adds static library which contains interception object file +# (universal binary on Mac and arch-specific object files on Linux). +macro(add_interceptor_lib library) + message(" --> add_interceptor_lib ${library} with " ${ARGN}) + add_library(${library} STATIC ${ARGN}) + set_target_properties(${library} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +endmacro() + +function(get_interception_lib_for_arch arch lib lib_name) + if(APPLE) + set(tgt_name "RTInterception.test.osx") + else() + set(tgt_name "RTInterception.test.${arch}") + endif() + set(${lib} "${tgt_name}" PARENT_SCOPE) + if(CMAKE_CONFIGURATION_TYPES) + set(configuration_path "${CMAKE_CFG_INTDIR}/") + else() + set(configuration_path "") + endif() + if(NOT MSVC) + set(${lib_name} "${configuration_path}lib${tgt_name}.a" PARENT_SCOPE) + else() + set(${lib_name} "${configuration_path}${tgt_name}.lib" PARENT_SCOPE) + endif() +endfunction() + +# Interception unit tests testsuite. +add_custom_target(InterceptionUnitTests) +set_target_properties(InterceptionUnitTests PROPERTIES + FOLDER "Compiler-RT Tests") + +# Adds interception tests for architecture. +macro(add_interception_tests_for_arch arch) + get_target_flags_for_arch(${arch} TARGET_FLAGS) + set(INTERCEPTION_TEST_SOURCES ${INTERCEPTION_UNITTESTS} + ${COMPILER_RT_GTEST_SOURCE}) + set(INTERCEPTION_TEST_COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS}) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND INTERCEPTION_TEST_COMPILE_DEPS gtest) + endif() + set(INTERCEPTION_TEST_OBJECTS) + foreach(source ${INTERCEPTION_TEST_SOURCES}) + get_filename_component(basename ${source} NAME) + if(CMAKE_CONFIGURATION_TYPES) + set(output_obj "${CMAKE_CFG_INTDIR}/${basename}.${arch}.o") + else() + set(output_obj "${basename}.${arch}.o") + endif() + clang_compile(${output_obj} ${source} + CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON} ${TARGET_FLAGS} + DEPS ${INTERCEPTION_TEST_COMPILE_DEPS}) + list(APPEND INTERCEPTION_TEST_OBJECTS ${output_obj}) + endforeach() + get_interception_lib_for_arch(${arch} INTERCEPTION_COMMON_LIB + INTERCEPTION_COMMON_LIB_NAME) + # Add unittest target. + set(INTERCEPTION_TEST_NAME "Interception-${arch}-Test") + message(STATUS "Adding unittest: " + ${INTERCEPTION_TEST_NAME} " : " ${INTERCEPTION_COMMON_LIB_NAME} + " / " ${INTERCEPTION_COMMON_LIB}) + add_compiler_rt_test(InterceptionUnitTests ${INTERCEPTION_TEST_NAME} + OBJECTS ${INTERCEPTION_TEST_OBJECTS} + ${INTERCEPTION_COMMON_LIB_NAME} + DEPS ${INTERCEPTION_TEST_OBJECTS} ${INTERCEPTION_COMMON_LIB} + LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON} + ${TARGET_FLAGS}) + + +endmacro() + +message(STATUS "**** Generating Architecture ****") +if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) + # We use just-built clang to build interception unittests, so we must + # be sure that produced binaries would work. + if(APPLE) + add_interceptor_lib("RTInterception.test.osx" + $) + else() + foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH}) + add_interceptor_lib("RTInterception.test.${arch}" + $) + endforeach() + endif() + foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH}) + message(STATUS "Generating : " ${arch}) + add_interception_tests_for_arch(${arch}) + endforeach() +endif() + + Index: lib/interception/tests/interception_basic_test.cc =================================================================== --- /dev/null +++ lib/interception/tests/interception_basic_test.cc @@ -0,0 +1,51 @@ +//===-- interception_basic_test.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 ThreadSanitizer/AddressSanitizer runtime. +// Tests for interception.h. +// +//===----------------------------------------------------------------------===// +#include "interception/interception.h" + +#include "gtest/gtest.h" + +static int InterceptorFunctionCalled; + +DECLARE_REAL(int, isdigit, int); + +INTERCEPTOR(int, isdigit, int d) { + ++InterceptorFunctionCalled; + return d >= '0' && d <= '9'; +} + +// Too slow for debug build +#if !SANITIZER_DEBUG + +namespace __interception { + +TEST(Interception, Basic) { + ASSERT_TRUE(INTERCEPT_FUNCTION(isdigit)); + + // After interception, the counter should be incremented. + InterceptorFunctionCalled = 0; + EXPECT_NE(0, isdigit('1')); + EXPECT_EQ(1, InterceptorFunctionCalled); + EXPECT_EQ(0, isdigit('a')); + EXPECT_EQ(2, InterceptorFunctionCalled); + + // Calling the REAL function should not affect the counter. + InterceptorFunctionCalled = 0; + EXPECT_NE(0, REAL(isdigit)('1')); + EXPECT_EQ(0, REAL(isdigit)('a')); + EXPECT_EQ(0, InterceptorFunctionCalled); +} + +} // namespace __interception + +#endif // #if !SANITIZER_DEBUG Index: lib/interception/tests/interception_linux_test.cc =================================================================== --- /dev/null +++ lib/interception/tests/interception_linux_test.cc @@ -0,0 +1,38 @@ +//===-- interception_linux_test.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 ThreadSanitizer/AddressSanitizer runtime. +// Tests for interception_linux.h. +// +//===----------------------------------------------------------------------===// +#include "interception/interception.h" + +#include "gtest/gtest.h" + +// Too slow for debug build +#if !SANITIZER_DEBUG +#if SANITIZER_LINUX + +namespace __interception { + +TEST(Interception, GetRealFunctionAddress) { + uptr expected_malloc_address = (uptr)(void*)&malloc; + uptr malloc_address = 0; + EXPECT_TRUE(GetRealFunctionAddress("malloc", &malloc_address, 0, 0)); + EXPECT_EQ(expected_malloc_address, malloc_address); + + uptr dummy_address = 0; + EXPECT_TRUE(GetRealFunctionAddress("dummy_doesnt_exist__", &dummy_address, 0, 0)); + EXPECT_EQ(0U, dummy_address); +} + +} // namespace __interception + +#endif // SANITIZER_LINUX +#endif // #if !SANITIZER_DEBUG Index: lib/interception/tests/interception_test_main.cc =================================================================== --- /dev/null +++ lib/interception/tests/interception_test_main.cc @@ -0,0 +1,22 @@ +//===-- interception_test_main.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 AddressSanitizer, an address sanity checker. +// +// Testing the machinery for providing replacements/wrappers for system +// functions. +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} Index: lib/interception/tests/interception_win_test.cc =================================================================== --- /dev/null +++ lib/interception/tests/interception_win_test.cc @@ -0,0 +1,41 @@ +//===-- interception_win_test.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 ThreadSanitizer/AddressSanitizer runtime. +// Tests for interception_win.h. +// +//===----------------------------------------------------------------------===// +#include "interception/interception.h" + +#include "gtest/gtest.h" + +// Too slow for debug build +#if !SANITIZER_DEBUG +#if SANITIZER_WINDOWS + +namespace __interception { + +// Tests for interception_win.h +TEST(Interception, InternalGetProcAddress) { + // TODO(etienneb): Implement me +} + +TEST(Interception, OverrideFunction) { + // TODO(etienneb): Implement me +} + +TEST(Interception, OverrideImportedFunction) { + // TODO(etienneb): Implement me +} + +// TODO: INTERCEPTOR_WINAPI +} // namespace __interception + +#endif // SANITIZER_WINDOWS +#endif // #if !SANITIZER_DEBUG