[compiler-rt] r274657 - [compilter-rt] Add unittests for interception library

Etienne Bergeron via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 6 12:15:11 PDT 2016


Author: etienneb
Date: Wed Jul  6 14:15:11 2016
New Revision: 274657

URL: http://llvm.org/viewvc/llvm-project?rev=274657&view=rev
Log:
[compilter-rt] Add unittests for interception library

Summary:
This patch is adding unittests for the interception library.


Reviewers: rnk

Subscribers: majnemer, llvm-commits, wang0109, chrisha, tberghammer, danalbert, srhines

Differential Revision: http://reviews.llvm.org/D21980

Added:
    compiler-rt/trunk/lib/interception/tests/
    compiler-rt/trunk/lib/interception/tests/CMakeLists.txt
    compiler-rt/trunk/lib/interception/tests/interception_linux_test.cc
    compiler-rt/trunk/lib/interception/tests/interception_test_main.cc
    compiler-rt/trunk/lib/interception/tests/interception_win_test.cc
Modified:
    compiler-rt/trunk/lib/interception/CMakeLists.txt
    compiler-rt/trunk/lib/interception/interception_win.cc

Modified: compiler-rt/trunk/lib/interception/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/CMakeLists.txt?rev=274657&r1=274656&r2=274657&view=diff
==============================================================================
--- compiler-rt/trunk/lib/interception/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/interception/CMakeLists.txt Wed Jul  6 14:15:11 2016
@@ -17,3 +17,7 @@ add_compiler_rt_object_libraries(RTInter
     ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
     SOURCES ${INTERCEPTION_SOURCES}
     CFLAGS ${INTERCEPTION_CFLAGS})
+
+if(COMPILER_RT_INCLUDE_TESTS)
+  add_subdirectory(tests)
+endif()

Modified: compiler-rt/trunk/lib/interception/interception_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/interception_win.cc?rev=274657&r1=274656&r2=274657&view=diff
==============================================================================
--- compiler-rt/trunk/lib/interception/interception_win.cc (original)
+++ compiler-rt/trunk/lib/interception/interception_win.cc Wed Jul  6 14:15:11 2016
@@ -201,6 +201,7 @@ static size_t RoundUpToInstrBoundary(siz
   size_t cursor = 0;
   while (cursor < size) {
     switch (code[cursor]) {
+      case '\x50':  // push eax
       case '\x51':  // push ecx
       case '\x52':  // push edx
       case '\x53':  // push ebx
@@ -341,7 +342,7 @@ bool OverrideFunction(uptr old_func, upt
 }
 
 static void **InterestingDLLsAvailable() {
-  const char *InterestingDLLs[] = {
+  static const char *InterestingDLLs[] = {
       "kernel32.dll",
       "msvcr110.dll",      // VS2012
       "msvcr120.dll",      // VS2013

Added: compiler-rt/trunk/lib/interception/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/tests/CMakeLists.txt?rev=274657&view=auto
==============================================================================
--- compiler-rt/trunk/lib/interception/tests/CMakeLists.txt (added)
+++ compiler-rt/trunk/lib/interception/tests/CMakeLists.txt Wed Jul  6 14:15:11 2016
@@ -0,0 +1,147 @@
+include(CompilerRTCompile)
+
+clang_compiler_add_cxx_check()
+
+filter_available_targets(INTERCEPTION_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el)
+
+set(INTERCEPTION_UNITTESTS
+  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)
+  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")
+  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()
+
+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"
+                        $<TARGET_OBJECTS:RTInterception.osx>)
+  else()
+    foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH})
+      add_interceptor_lib("RTInterception.test.${arch}"
+                          $<TARGET_OBJECTS:RTInterception.${arch}>)
+    endforeach()
+  endif()
+  foreach(arch ${INTERCEPTION_UNITTEST_SUPPORTED_ARCH})
+    add_interception_tests_for_arch(${arch})
+  endforeach()
+endif()
+
+

Added: compiler-rt/trunk/lib/interception/tests/interception_linux_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/tests/interception_linux_test.cc?rev=274657&view=auto
==============================================================================
--- compiler-rt/trunk/lib/interception/tests/interception_linux_test.cc (added)
+++ compiler-rt/trunk/lib/interception/tests/interception_linux_test.cc Wed Jul  6 14:15:11 2016
@@ -0,0 +1,65 @@
+//===-- 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
+
+static int InterceptorFunctionCalled;
+
+DECLARE_REAL(int, isdigit, int);
+
+INTERCEPTOR(int, isdigit, int d) {
+  ++InterceptorFunctionCalled;
+  return d >= '0' && d <= '9';
+}
+
+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);
+}
+
+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  // SANITIZER_LINUX
+#endif  // #if !SANITIZER_DEBUG

Added: compiler-rt/trunk/lib/interception/tests/interception_test_main.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/tests/interception_test_main.cc?rev=274657&view=auto
==============================================================================
--- compiler-rt/trunk/lib/interception/tests/interception_test_main.cc (added)
+++ compiler-rt/trunk/lib/interception/tests/interception_test_main.cc Wed Jul  6 14:15:11 2016
@@ -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();
+}

Added: compiler-rt/trunk/lib/interception/tests/interception_win_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/tests/interception_win_test.cc?rev=274657&view=auto
==============================================================================
--- compiler-rt/trunk/lib/interception/tests/interception_win_test.cc (added)
+++ compiler-rt/trunk/lib/interception/tests/interception_win_test.cc Wed Jul  6 14:15:11 2016
@@ -0,0 +1,142 @@
+//===-- 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
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace {
+
+typedef int (*IdentityFunction)(int);
+
+#if !SANITIZER_WINDOWS64
+u8 kIdentityCodeWithPrologue[] = {
+    0x55,              // push        ebp
+    0x8B, 0xEC,        // mov         ebp,esp
+    0x8B, 0x45, 0x08,  // mov         eax,dword ptr [ebp + 8]
+    0x5D,              // pop         ebp
+    0xC3,              // ret
+};
+
+u8 kIdentityCodeWithPushPop[] = {
+    0x55,              // push        ebp
+    0x8B, 0xEC,        // mov         ebp,esp
+    0x53,              // push        ebx
+    0x50,              // push        eax
+    0x58,              // pop         eax
+    0x8B, 0x45, 0x08,  // mov         eax,dword ptr [ebp + 8]
+    0x5B,              // pop         ebx
+    0x5D,              // pop         ebp
+    0xC3,              // ret
+};
+
+#endif
+
+// A buffer holding the dynamically generated code under test.
+u8* ActiveCode;
+size_t ActiveCodeLength = 4096;
+
+bool LoadActiveCode(u8* Code, size_t CodeLength, uptr* EntryPoint) {
+  if (ActiveCode == nullptr) {
+    ActiveCode =
+        (u8*)::VirtualAlloc(nullptr, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
+                            PAGE_EXECUTE_READWRITE);
+    if (ActiveCode == nullptr) return false;
+  }
+
+  size_t Position = 0;
+  *EntryPoint = (uptr)&ActiveCode[0];
+
+  // Copy the function body.
+  for (size_t i = 0; i < CodeLength; ++i)
+  	ActiveCode[Position++] = Code[i];
+
+  return true;
+}
+
+int InterceptorFunctionCalled;
+
+NOINLINE int InterceptorFunction(int x) {
+  ++InterceptorFunctionCalled;
+  return x;
+}
+
+}  // namespace
+
+namespace __interception {
+
+// Tests for interception_win.h
+TEST(Interception, InternalGetProcAddress) {
+  HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
+  ASSERT_NE(nullptr, ntdll_handle);
+  uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
+  uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
+  uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
+  uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
+
+  EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
+  EXPECT_EQ(isdigit_expected, isdigit_address);
+  EXPECT_NE(DbgPrint_adddress, isdigit_address);
+}
+
+void TestIdentityFunctionPatching(u8* IdentityCode, size_t IdentityCodeLength) {
+  uptr IdentityAddress;
+  ASSERT_TRUE(
+      LoadActiveCode(IdentityCode, IdentityCodeLength, &IdentityAddress));
+  IdentityFunction Identity = (IdentityFunction)IdentityAddress;
+
+  // Validate behavior before dynamic patching.
+  InterceptorFunctionCalled = 0;
+  EXPECT_EQ(0, Identity(0));
+  EXPECT_EQ(42, Identity(42));
+  EXPECT_EQ(0, InterceptorFunctionCalled);
+
+  // Patch the function.
+  uptr RealIdentityAddress = 0;
+  EXPECT_TRUE(OverrideFunction(IdentityAddress, (uptr)&InterceptorFunction,
+                               &RealIdentityAddress));
+  IdentityFunction RealIdentity = (IdentityFunction)RealIdentityAddress;
+
+  // Calling the redirected function.
+  InterceptorFunctionCalled = 0;
+  EXPECT_EQ(0, Identity(0));
+  EXPECT_EQ(42, Identity(42));
+  EXPECT_EQ(2, InterceptorFunctionCalled);
+
+  // Calling the real function.
+  InterceptorFunctionCalled = 0;
+  EXPECT_EQ(0, RealIdentity(0));
+  EXPECT_EQ(42, RealIdentity(42));
+  EXPECT_EQ(0, InterceptorFunctionCalled);
+}
+
+#if !SANITIZER_WINDOWS64
+TEST(Interception, OverrideFunction) {
+  TestIdentityFunctionPatching(kIdentityCodeWithPrologue,
+                               sizeof(kIdentityCodeWithPrologue));
+  TestIdentityFunctionPatching(kIdentityCodeWithPushPop,
+                               sizeof(kIdentityCodeWithPushPop));
+}
+#endif
+
+}  // namespace __interception
+
+#endif  // SANITIZER_WINDOWS
+#endif  // #if !SANITIZER_DEBUG




More information about the llvm-commits mailing list