aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sanitizer_common/tests')
-rw-r--r--lib/sanitizer_common/tests/CMakeLists.txt109
-rw-r--r--lib/sanitizer_common/tests/lit.site.cfg.in14
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_test.cc81
-rw-r--r--lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc4
-rw-r--r--lib/sanitizer_common/tests/sanitizer_atomic_test.cc73
-rw-r--r--lib/sanitizer_common/tests/sanitizer_bitvector_test.cc176
-rw-r--r--lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc339
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc46
-rw-r--r--lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc496
-rw-r--r--lib/sanitizer_common/tests/sanitizer_flags_test.cc12
-rw-r--r--lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc (renamed from lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc)141
-rw-r--r--lib/sanitizer_common/tests/sanitizer_ioctl_test.cc26
-rw-r--r--lib/sanitizer_common/tests/sanitizer_libc_test.cc3
-rw-r--r--lib/sanitizer_common/tests/sanitizer_mutex_test.cc15
-rw-r--r--lib/sanitizer_common/tests/sanitizer_posix_test.cc18
-rw-r--r--lib/sanitizer_common/tests/sanitizer_printf_test.cc23
-rw-r--r--lib/sanitizer_common/tests/sanitizer_procmaps_test.cc37
-rw-r--r--lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h66
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc87
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc122
-rw-r--r--lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc65
-rw-r--r--lib/sanitizer_common/tests/sanitizer_suppressions_test.cc26
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_config.h30
-rw-r--r--lib/sanitizer_common/tests/sanitizer_test_utils.h63
-rw-r--r--lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc13
25 files changed, 1863 insertions, 222 deletions
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 5b66917b05b0..bb7a399b0ec6 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -1,10 +1,16 @@
include(CompilerRTCompile)
+clang_compiler_add_cxx_check()
+
set(SANITIZER_UNITTESTS
sanitizer_allocator_test.cc
sanitizer_atomic_test.cc
+ sanitizer_bitvector_test.cc
+ sanitizer_bvgraph_test.cc
sanitizer_common_test.cc
+ sanitizer_deadlock_detector_test.cc
sanitizer_flags_test.cc
+ sanitizer_format_interceptor_test.cc
sanitizer_ioctl_test.cc
sanitizer_libc_test.cc
sanitizer_linux_test.cc
@@ -13,8 +19,9 @@ set(SANITIZER_UNITTESTS
sanitizer_nolibc_test.cc
sanitizer_posix_test.cc
sanitizer_printf_test.cc
- sanitizer_scanf_interceptor_test.cc
+ sanitizer_procmaps_test.cc
sanitizer_stackdepot_test.cc
+ sanitizer_stacktrace_printer_test.cc
sanitizer_stacktrace_test.cc
sanitizer_stoptheworld_test.cc
sanitizer_suppressions_test.cc
@@ -22,22 +29,47 @@ set(SANITIZER_UNITTESTS
sanitizer_thread_registry_test.cc)
set(SANITIZER_TEST_HEADERS
+ sanitizer_pthread_wrappers.h
+ sanitizer_test_config.h
sanitizer_test_utils.h)
foreach(header ${SANITIZER_HEADERS})
list(APPEND SANITIZER_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
endforeach()
set(SANITIZER_TEST_CFLAGS_COMMON
- ${COMPILER_RT_GTEST_INCLUDE_CFLAGS}
+ ${COMPILER_RT_TEST_CFLAGS}
+ ${COMPILER_RT_GTEST_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib
-I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common
- -DGTEST_HAS_RTTI=0
- -O2 -g -fno-rtti
- -Wall -Werror -Werror=sign-compare)
+ -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 ASAN_UNITTEST_COMMON_CFLAGS -gline-tables-only)
+else()
+ list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -g)
+endif()
+
+if(NOT MSVC)
+ list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON --driver-mode=g++)
+endif()
+
+set(SANITIZER_TEST_LINK_LIBS)
+append_list_if(ANDROID log SANITIZER_TEST_LINK_LIBS)
+# NDK r10 requires -latomic almost always.
+append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS)
-set(SANITIZER_TEST_LINK_FLAGS_COMMON
- -lstdc++ -ldl)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread SANITIZER_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 SANITIZER_TEST_LINK_FLAGS_COMMON "-lc++ -lm")
+endif()
include_directories(..)
include_directories(../..)
@@ -57,7 +89,11 @@ function(get_sanitizer_common_lib_for_arch arch lib lib_name)
set(tgt_name "RTSanitizerCommon.test.${arch}")
endif()
set(${lib} "${tgt_name}" PARENT_SCOPE)
- set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+ if(NOT MSVC)
+ set(${lib_name} "lib${tgt_name}.a" PARENT_SCOPE)
+ else()
+ set(${lib_name} "${tgt_name}.lib" PARENT_SCOPE)
+ endif()
endfunction()
# Sanitizer_common unit tests testsuite.
@@ -70,14 +106,17 @@ macro(add_sanitizer_tests_for_arch arch)
get_target_flags_for_arch(${arch} TARGET_FLAGS)
set(SANITIZER_TEST_SOURCES ${SANITIZER_UNITTESTS}
${COMPILER_RT_GTEST_SOURCE})
+ set(SANITIZER_TEST_COMPILE_DEPS ${SANITIZER_TEST_HEADERS})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SANITIZER_TEST_COMPILE_DEPS gtest)
+ endif()
set(SANITIZER_TEST_OBJECTS)
foreach(source ${SANITIZER_TEST_SOURCES})
get_filename_component(basename ${source} NAME)
set(output_obj "${basename}.${arch}.o")
clang_compile(${output_obj} ${source}
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
- DEPS gtest ${SANITIZER_RUNTIME_LIBRARIES}
- ${SANITIZER_TEST_HEADERS})
+ DEPS ${SANITIZER_TEST_COMPILE_DEPS})
list(APPEND SANITIZER_TEST_OBJECTS ${output_obj})
endforeach()
get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB
@@ -89,7 +128,7 @@ macro(add_sanitizer_tests_for_arch arch)
${SANITIZER_COMMON_LIB_NAME}
DEPS ${SANITIZER_TEST_OBJECTS} ${SANITIZER_COMMON_LIB}
LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON}
- -lpthread ${TARGET_FLAGS})
+ ${TARGET_FLAGS})
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
# Test that the libc-independent part of sanitizer_common is indeed
@@ -98,7 +137,7 @@ macro(add_sanitizer_tests_for_arch arch)
clang_compile(sanitizer_nolibc_test_main.${arch}.o
sanitizer_nolibc_test_main.cc
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
- DEPS ${SANITIZER_RUNTIME_LIBRARIES} ${SANITIZER_TEST_HEADERS})
+ DEPS ${SANITIZER_TEST_COMPILE_DEPS})
add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc"
OBJECTS sanitizer_nolibc_test_main.${arch}.o
-Wl,-whole-archive
@@ -110,7 +149,7 @@ macro(add_sanitizer_tests_for_arch arch)
endif()
endmacro()
-if(COMPILER_RT_CAN_EXECUTE_TESTS)
+if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID)
# We use just-built clang to build sanitizer_common unittests, so we must
# be sure that produced binaries would work.
if(APPLE)
@@ -136,34 +175,24 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
if(CAN_TARGET_i386)
add_sanitizer_tests_for_arch(i386)
endif()
-
- # Run unittests as a part of lit testsuite.
- configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- )
-
- add_lit_testsuite(check-sanitizer "Running sanitizer library unittests"
- ${CMAKE_CURRENT_BINARY_DIR}
- DEPENDS SanitizerUnitTests
- )
- set_target_properties(check-sanitizer PROPERTIES FOLDER "Sanitizer unittests")
endif()
if(ANDROID)
- # We assume that unit tests on Android are built in a build
- # tree with fresh Clang as a host compiler.
- add_executable(SanitizerTest
- ${SANITIZER_UNITTESTS}
- ${COMPILER_RT_GTEST_SOURCE}
- $<TARGET_OBJECTS:RTSanitizerCommon.arm.android>)
- set_target_compile_flags(SanitizerTest
- ${SANITIZER_COMMON_CFLAGS}
- ${SANITIZER_TEST_CFLAGS_COMMON})
- # Setup correct output directory and link flags.
- set_target_properties(SanitizerTest PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
- set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
- # Add unit test to test suite.
- add_dependencies(SanitizerUnitTests SanitizerTest)
+ foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH})
+ add_executable(SanitizerTest
+ ${SANITIZER_UNITTESTS}
+ ${COMPILER_RT_GTEST_SOURCE}
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
+ set_target_compile_flags(SanitizerTest
+ ${SANITIZER_COMMON_CFLAGS}
+ ${SANITIZER_TEST_CFLAGS_COMMON})
+ # Setup correct output directory and link flags.
+ set_target_properties(SanitizerTest PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ set_target_link_flags(SanitizerTest ${SANITIZER_TEST_LINK_FLAGS_COMMON})
+ target_link_libraries(SanitizerTest ${SANITIZER_TEST_LINK_LIBS})
+ # Add unit test to test suite.
+ add_dependencies(SanitizerUnitTests SanitizerTest)
+ endforeach()
endif()
diff --git a/lib/sanitizer_common/tests/lit.site.cfg.in b/lib/sanitizer_common/tests/lit.site.cfg.in
deleted file mode 100644
index 5ceb9e4c5c28..000000000000
--- a/lib/sanitizer_common/tests/lit.site.cfg.in
+++ /dev/null
@@ -1,14 +0,0 @@
-## Autogenerated by LLVM/Clang configuration.
-# Do not edit!
-
-# Load common config for all compiler-rt unit tests.
-lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured")
-
-# Setup config name.
-config.name = 'SanitizerCommon-Unit'
-
-# Setup test source and exec root. For unit tests, we define
-# it as build directory with sanitizer_common tests.
-config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", "lib",
- "sanitizer_common", "tests")
-config.test_source_root = config.test_exec_root
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index d92a07fe4c2d..f61d58dea7d9 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -17,11 +17,11 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_test_utils.h"
+#include "sanitizer_pthread_wrappers.h"
#include "gtest/gtest.h"
#include <stdlib.h>
-#include <pthread.h>
#include <algorithm>
#include <vector>
#include <set>
@@ -328,6 +328,7 @@ TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
}
#endif
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
TEST(SanitizerCommon, LargeMmapAllocator) {
LargeMmapAllocator<> a;
a.Init();
@@ -403,6 +404,7 @@ TEST(SanitizerCommon, LargeMmapAllocator) {
CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size));
a.Deallocate(&stats, p);
}
+#endif
template
<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
@@ -477,11 +479,13 @@ TEST(SanitizerCommon, CombinedAllocator64Compact) {
}
#endif
+#if !defined(_WIN32) // FIXME: This currently fails on Windows.
TEST(SanitizerCommon, CombinedAllocator32Compact) {
TestCombinedAllocator<Allocator32Compact,
LargeMmapAllocator<>,
SizeClassAllocatorLocalCache<Allocator32Compact> > ();
}
+#endif
template <class AllocatorCache>
void TestSizeClassAllocatorLocalCache() {
@@ -553,8 +557,8 @@ TEST(SanitizerCommon, AllocatorLeakTest) {
uptr total_used_memory = 0;
for (int i = 0; i < 100; i++) {
pthread_t t;
- EXPECT_EQ(0, pthread_create(&t, 0, AllocatorLeakTestWorker, &a));
- EXPECT_EQ(0, pthread_join(t, 0));
+ PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a);
+ PTHREAD_JOIN(t, 0);
if (i == 0)
total_used_memory = a.TotalMemoryUsed();
EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory);
@@ -595,8 +599,8 @@ TEST(Allocator, AllocatorCacheDeallocNewThread) {
params->allocator = &allocator;
params->class_id = class_id;
pthread_t t;
- EXPECT_EQ(0, pthread_create(&t, 0, DeallocNewThreadWorker, params));
- EXPECT_EQ(0, pthread_join(t, 0));
+ PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params);
+ PTHREAD_JOIN(t, 0);
}
#endif
@@ -625,9 +629,9 @@ TEST(Allocator, Stress) {
}
}
-TEST(Allocator, InternalAllocFailure) {
- EXPECT_DEATH(Ident(InternalAlloc(10 << 20)),
- "Unexpected mmap in InternalAllocator!");
+TEST(Allocator, LargeAlloc) {
+ void *p = InternalAlloc(10 << 20);
+ InternalFree(p);
}
TEST(Allocator, ScopedBuffer) {
@@ -794,4 +798,65 @@ TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) {
}
#endif
+TEST(SanitizerCommon, TwoLevelByteMap) {
+ const u64 kSize1 = 1 << 6, kSize2 = 1 << 12;
+ const u64 n = kSize1 * kSize2;
+ TwoLevelByteMap<kSize1, kSize2> m;
+ m.TestOnlyInit();
+ for (u64 i = 0; i < n; i += 7) {
+ m.set(i, (i % 100) + 1);
+ }
+ for (u64 j = 0; j < n; j++) {
+ if (j % 7)
+ EXPECT_EQ(m[j], 0);
+ else
+ EXPECT_EQ(m[j], (j % 100) + 1);
+ }
+
+ m.TestOnlyUnmap();
+}
+
+
+typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
+
+struct TestByteMapParam {
+ TestByteMap *m;
+ size_t shard;
+ size_t num_shards;
+};
+
+void *TwoLevelByteMapUserThread(void *param) {
+ TestByteMapParam *p = (TestByteMapParam*)param;
+ for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) {
+ size_t val = (i % 100) + 1;
+ p->m->set(i, val);
+ EXPECT_EQ((*p->m)[i], val);
+ }
+ return 0;
+}
+
+TEST(SanitizerCommon, ThreadedTwoLevelByteMap) {
+ TestByteMap m;
+ m.TestOnlyInit();
+ TestMapUnmapCallback::map_count = 0;
+ TestMapUnmapCallback::unmap_count = 0;
+ static const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ TestByteMapParam p[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++) {
+ p[i].m = &m;
+ p[i].shard = i;
+ p[i].num_shards = kNumThreads;
+ PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]);
+ }
+ for (int i = 0; i < kNumThreads; i++) {
+ PTHREAD_JOIN(t[i], 0);
+ }
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL);
+ m.TestOnlyUnmap();
+ EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1());
+ EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1());
+}
+
#endif // #if TSAN_DEBUG==0
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
index f6a944f68f5e..0cc3b9ba6944 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cc
@@ -156,7 +156,7 @@ void *operator new(size_t size) ALIAS("malloc");
void *operator new[](size_t size) ALIAS("malloc");
void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc");
void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc");
-void operator delete(void *ptr) ALIAS("free");
-void operator delete[](void *ptr) ALIAS("free");
+void operator delete(void *ptr) throw() ALIAS("free");
+void operator delete[](void *ptr) throw() ALIAS("free");
void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free");
void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free");
diff --git a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
index a4a97c43e00f..56bcd35c826c 100644
--- a/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_atomic_test.cc
@@ -15,6 +15,79 @@
namespace __sanitizer {
+template<typename T>
+struct ValAndMagic {
+ typename T::Type magic0;
+ T a;
+ typename T::Type magic1;
+
+ static ValAndMagic<T> *sink;
+};
+
+template<typename T>
+ValAndMagic<T> *ValAndMagic<T>::sink;
+
+template<typename T, memory_order load_mo, memory_order store_mo>
+void CheckStoreLoad() {
+ typedef typename T::Type Type;
+ ValAndMagic<T> val;
+ // Prevent the compiler from scalarizing the struct.
+ ValAndMagic<T>::sink = &val;
+ // Ensure that surrounding memory is not overwritten.
+ val.magic0 = val.magic1 = (Type)-3;
+ for (u64 i = 0; i < 100; i++) {
+ // Generate a value that occupies all bytes of the variable.
+ u64 v = i;
+ v |= v << 8;
+ v |= v << 16;
+ v |= v << 32;
+ val.a.val_dont_use = (Type)v;
+ EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
+ val.a.val_dont_use = (Type)-1;
+ atomic_store(&val.a, (Type)v, store_mo);
+ EXPECT_EQ(val.a.val_dont_use, (Type)v);
+ }
+ EXPECT_EQ(val.magic0, (Type)-3);
+ EXPECT_EQ(val.magic1, (Type)-3);
+}
+
+TEST(SanitizerCommon, AtomicStoreLoad) {
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
+ CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
+
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
+ ();
+ CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
+ ();
+}
+
// Clang crashes while compiling this test for Android:
// http://llvm.org/bugs/show_bug.cgi?id=15587
#if !SANITIZER_ANDROID
diff --git a/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
new file mode 100644
index 000000000000..706b4c58968e
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bitvector_test.cc
@@ -0,0 +1,176 @@
+//===-- sanitizer_bitvector_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 Sanitizer runtime.
+// Tests for sanitizer_bitvector.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bitvector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+
+// Check the 'bv' == 's' and that the indexes go in increasing order.
+// Also check the BV::Iterator
+template <class BV>
+static void CheckBV(const BV &bv, const set<uptr> &s) {
+ BV t;
+ t.copyFrom(bv);
+ set<uptr> t_s(s);
+ uptr last_idx = bv.size();
+ uptr count = 0;
+ for (typename BV::Iterator it(bv); it.hasNext();) {
+ uptr idx = it.next();
+ count++;
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(s.count(idx));
+ }
+ EXPECT_EQ(count, s.size());
+
+ last_idx = bv.size();
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ if (last_idx != bv.size())
+ EXPECT_LT(last_idx, idx);
+ last_idx = idx;
+ EXPECT_TRUE(t_s.erase(idx));
+ }
+ EXPECT_TRUE(t_s.empty());
+}
+
+template <class BV>
+void Print(const BV &bv) {
+ BV t;
+ t.copyFrom(bv);
+ while (!t.empty()) {
+ uptr idx = t.getAndClearFirstOne();
+ fprintf(stderr, "%zd ", idx);
+ }
+ fprintf(stderr, "\n");
+}
+
+void Print(const set<uptr> &s) {
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
+ fprintf(stderr, "%zd ", *it);
+ }
+ fprintf(stderr, "\n");
+}
+
+template <class BV>
+void TestBitVector(uptr expected_size) {
+ BV bv, bv1, t_bv;
+ EXPECT_EQ(expected_size, BV::kSize);
+ bv.clear();
+ EXPECT_TRUE(bv.empty());
+ bv.setBit(5);
+ EXPECT_FALSE(bv.empty());
+ EXPECT_FALSE(bv.getBit(4));
+ EXPECT_FALSE(bv.getBit(6));
+ EXPECT_TRUE(bv.getBit(5));
+ bv.clearBit(5);
+ EXPECT_FALSE(bv.getBit(5));
+
+ // test random bits
+ bv.clear();
+ set<uptr> s;
+ for (uptr it = 0; it < 1000; it++) {
+ uptr bit = ((uptr)my_rand() % bv.size());
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ switch (my_rand() % 2) {
+ case 0:
+ EXPECT_EQ(bv.setBit(bit), s.insert(bit).second);
+ break;
+ case 1:
+ size_t old_size = s.size();
+ s.erase(bit);
+ EXPECT_EQ(bv.clearBit(bit), old_size > s.size());
+ break;
+ }
+ EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
+ }
+
+ vector<uptr>bits(bv.size());
+ // Test setUnion, setIntersection, setDifference,
+ // intersectsWith, and getAndClearFirstOne.
+ for (uptr it = 0; it < 30; it++) {
+ // iota
+ for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
+ random_shuffle(bits.begin(), bits.end());
+ set<uptr> s, s1, t_s;
+ bv.clear();
+ bv1.clear();
+ uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
+ uptr n_bits1 = (uptr)my_rand() % (bv.size() / 2);
+ EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
+ EXPECT_TRUE(n_bits1 < bv.size() / 2);
+ for (uptr i = 0; i < n_bits; i++) {
+ bv.setBit(bits[i]);
+ s.insert(bits[i]);
+ }
+ CheckBV(bv, s);
+ for (uptr i = 0; i < n_bits1; i++) {
+ bv1.setBit(bits[bv.size() / 2 + i]);
+ s1.insert(bits[bv.size() / 2 + i]);
+ }
+ CheckBV(bv1, s1);
+
+ vector<uptr> vec;
+ set_intersection(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ EXPECT_EQ(bv.intersectsWith(bv1), !vec.empty());
+
+ // setUnion
+ t_s = s;
+ t_bv.copyFrom(bv);
+ t_s.insert(s1.begin(), s1.end());
+ EXPECT_EQ(t_bv.setUnion(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setIntersection
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setIntersection(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+
+ // setDifference
+ vec.clear();
+ set_difference(s.begin(), s.end(), s1.begin(), s1.end(),
+ back_insert_iterator<vector<uptr> >(vec));
+ t_s = set<uptr>(vec.begin(), vec.end());
+ t_bv.copyFrom(bv);
+ EXPECT_EQ(t_bv.setDifference(bv1), s.size() != t_s.size());
+ CheckBV(t_bv, t_s);
+ }
+}
+
+TEST(SanitizerCommon, BasicBitVector) {
+ TestBitVector<BasicBitVector<u8> >(8);
+ TestBitVector<BasicBitVector<u16> >(16);
+ TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
+}
+
+TEST(SanitizerCommon, TwoLevelBitVector) {
+ uptr ws = SANITIZER_WORDSIZE;
+ TestBitVector<TwoLevelBitVector<1, BasicBitVector<u8> > >(8 * 8);
+ TestBitVector<TwoLevelBitVector<> >(ws * ws);
+ TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
+ TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
+ TestBitVector<TwoLevelBitVector<3, BasicBitVector<u16> > >(16 * 16 * 3);
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
new file mode 100644
index 000000000000..3b39f8dd734a
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc
@@ -0,0 +1,339 @@
+//===-- sanitizer_bvgraph_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 Sanitizer runtime.
+// Tests for sanitizer_bvgraph.h.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_bvgraph.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+template<class G>
+void PrintGraph(const G &g) {
+ for (uptr i = 0; i < g.size(); i++) {
+ for (uptr j = 0; j < g.size(); j++) {
+ fprintf(stderr, "%d", g.hasEdge(i, j));
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+
+class SimpleGraph {
+ public:
+ void clear() { s_.clear(); }
+ bool addEdge(uptr from, uptr to) {
+ return s_.insert(idx(from, to)).second;
+ }
+ bool removeEdge(uptr from, uptr to) {
+ return s_.erase(idx(from, to));
+ }
+ template <class G>
+ void checkSameAs(G *g) {
+ for (set<uptr>::iterator it = s_.begin(); it != s_.end(); ++it) {
+ uptr from = *it >> 16;
+ uptr to = *it & ((1 << 16) - 1);
+ EXPECT_TRUE(g->removeEdge(from, to));
+ }
+ EXPECT_TRUE(g->empty());
+ }
+ private:
+ uptr idx(uptr from, uptr to) {
+ CHECK_LE(from|to, 1 << 16);
+ return (from << 16) + to;
+ }
+ set<uptr> s_;
+};
+
+template <class BV>
+void BasicTest() {
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ SimpleGraph s_g;
+ set<uptr> s;
+ set<uptr> s_target;
+ int num_reachable = 0;
+ for (int it = 0; it < 1000; it++) {
+ target.clear();
+ s_target.clear();
+ for (int t = 0; t < 4; t++) {
+ uptr idx = (uptr)my_rand() % g.size();
+ EXPECT_EQ(target.setBit(idx), s_target.insert(idx).second);
+ }
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ EXPECT_TRUE(g.hasEdge(from, to));
+ for (int i = 0; i < 10; i++) {
+ from = my_rand() % g.size();
+ bool is_reachable = g.isReachable(from, target);
+ if (is_reachable) {
+ uptr path[BV::kSize];
+ uptr len;
+ for (len = 1; len < BV::kSize; len++) {
+ if (g.findPath(from, target, path, len) == len)
+ break;
+ }
+ EXPECT_LT(len, BV::kSize);
+ EXPECT_TRUE(target.getBit(path[len - 1]));
+ // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n",
+ // from, len, path[0], path[1], path[2]);
+ num_reachable++;
+ }
+ }
+ }
+ EXPECT_GT(num_reachable, 0);
+}
+
+TEST(BVGraph, BasicTest) {
+ BasicTest<BV1>();
+ BasicTest<BV2>();
+ BasicTest<BV3>();
+ BasicTest<BV4>();
+}
+
+template <class BV>
+void RemoveEdges() {
+ SimpleGraph s_g;
+ BVGraph<BV> g;
+ g.clear();
+ BV bv;
+ set<uptr> s;
+ for (int it = 0; it < 100; it++) {
+ s.clear();
+ bv.clear();
+ s_g.clear();
+ g.clear();
+ for (uptr j = 0; j < g.size() * 2; j++) {
+ uptr from = my_rand() % g.size();
+ uptr to = my_rand() % g.size();
+ EXPECT_EQ(g.addEdge(from, to), s_g.addEdge(from, to));
+ }
+ for (uptr j = 0; j < 5; j++) {
+ uptr idx = my_rand() % g.size();
+ s.insert(idx);
+ bv.setBit(idx);
+ }
+
+ if (it % 2) {
+ g.removeEdgesFrom(bv);
+ for (set<uptr>::iterator from = s.begin(); from != s.end(); ++from) {
+ for (uptr to = 0; to < g.size(); to++)
+ s_g.removeEdge(*from, to);
+ }
+ } else {
+ g.removeEdgesTo(bv);
+ for (set<uptr>::iterator to = s.begin(); to != s.end(); ++to) {
+ for (uptr from = 0; from < g.size(); from++)
+ s_g.removeEdge(from, *to);
+ }
+ }
+ s_g.checkSameAs(&g);
+ }
+}
+
+TEST(BVGraph, RemoveEdges) {
+ RemoveEdges<BV1>();
+ RemoveEdges<BV2>();
+ RemoveEdges<BV3>();
+ RemoveEdges<BV4>();
+}
+
+template <class BV>
+void Test_isReachable() {
+ uptr path[5];
+ BVGraph<BV> g;
+ g.clear();
+ BV target;
+ target.clear();
+ uptr t0 = 0;
+ uptr t1 = g.size() - 1;
+ target.setBit(t0);
+ target.setBit(t1);
+
+ uptr f0 = 1;
+ uptr f1 = 2;
+ uptr f2 = g.size() / 2;
+ uptr f3 = g.size() - 2;
+
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f0, f1);
+ g.addEdge(f1, f2);
+ g.addEdge(f2, f3);
+ EXPECT_FALSE(g.isReachable(f0, target));
+ EXPECT_FALSE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+
+ g.addEdge(f1, t0);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_FALSE(g.isReachable(f2, target));
+ EXPECT_FALSE(g.isReachable(f3, target));
+ EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U);
+ EXPECT_EQ(path[0], f0);
+ EXPECT_EQ(path[1], f1);
+ EXPECT_EQ(path[2], t0);
+ EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U);
+ EXPECT_EQ(path[0], f1);
+ EXPECT_EQ(path[1], t0);
+
+ g.addEdge(f3, t1);
+ EXPECT_TRUE(g.isReachable(f0, target));
+ EXPECT_TRUE(g.isReachable(f1, target));
+ EXPECT_TRUE(g.isReachable(f2, target));
+ EXPECT_TRUE(g.isReachable(f3, target));
+}
+
+TEST(BVGraph, isReachable) {
+ Test_isReachable<BV1>();
+ Test_isReachable<BV2>();
+ Test_isReachable<BV3>();
+ Test_isReachable<BV4>();
+}
+
+template <class BV>
+void LongCycle() {
+ BVGraph<BV> g;
+ g.clear();
+ vector<uptr> path_vec(g.size());
+ uptr *path = path_vec.data();
+ uptr start = 5;
+ for (uptr i = start; i < g.size() - 1; i++) {
+ g.addEdge(i, i + 1);
+ for (uptr j = 0; j < start; j++)
+ g.addEdge(i, j);
+ }
+ // Bad graph that looks like this:
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 00000000000000
+ // 11111010000000
+ // 11111001000000
+ // 11111000100000
+ // 11111000010000
+ // 11111000001000
+ // 11111000000100
+ // 11111000000010
+ // 11111000000001
+ // if (g.size() <= 64) PrintGraph(g);
+ BV target;
+ for (uptr i = start + 1; i < g.size(); i += 11) {
+ // if ((i & (i - 1)) == 0) fprintf(stderr, "Path: : %zd\n", i);
+ target.clear();
+ target.setBit(i);
+ EXPECT_TRUE(g.isReachable(start, target));
+ EXPECT_EQ(g.findPath(start, target, path, g.size()), i - start + 1);
+ }
+}
+
+TEST(BVGraph, LongCycle) {
+ LongCycle<BV1>();
+ LongCycle<BV2>();
+ LongCycle<BV3>();
+ LongCycle<BV4>();
+}
+
+template <class BV>
+void ShortestPath() {
+ uptr path[8];
+ BVGraph<BV> g;
+ g.clear();
+ BV t7;
+ t7.clear();
+ t7.setBit(7);
+ // 1=>2=>3=>4=>5=>6=>7
+ // 1=>7
+ g.addEdge(1, 2);
+ g.addEdge(2, 3);
+ g.addEdge(3, 4);
+ g.addEdge(4, 5);
+ g.addEdge(5, 6);
+ g.addEdge(6, 7);
+ g.addEdge(1, 7);
+ EXPECT_TRUE(g.isReachable(1, t7));
+ // No path of length 1.
+ EXPECT_EQ(0U, g.findPath(1, t7, path, 1));
+ // Trying to find a path of len 2..6 gives path of len 2.
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 3));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 4));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 5));
+ EXPECT_EQ(2U, g.findPath(1, t7, path, 6));
+ // Trying to find a path of len 7 gives path of len 7, because this is DFS.
+ EXPECT_EQ(7U, g.findPath(1, t7, path, 7));
+ // But findShortestPath will find the shortest path.
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 2));
+ EXPECT_EQ(2U, g.findShortestPath(1, t7, path, 7));
+}
+
+TEST(BVGraph, ShortestPath) {
+ ShortestPath<BV1>();
+ ShortestPath<BV2>();
+ ShortestPath<BV3>();
+ ShortestPath<BV4>();
+}
+
+template <class BV>
+void RunAddEdgesTest() {
+ BVGraph<BV> g;
+ BV from;
+ const int kMaxEdges = 10;
+ uptr added_edges[kMaxEdges];
+ g.clear();
+ from.clear();
+ EXPECT_EQ(0U, g.addEdges(from, 0, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ from.setBit(0);
+ EXPECT_EQ(1U, g.addEdges(from, 1, added_edges, kMaxEdges));
+ EXPECT_EQ(0U, added_edges[0]);
+ EXPECT_EQ(0U, g.addEdges(from, 1, added_edges, kMaxEdges));
+
+ from.clear();
+ from.setBit(1);
+ EXPECT_EQ(1U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(1, 4));
+ EXPECT_FALSE(g.hasEdge(1, 5));
+ EXPECT_EQ(1U, added_edges[0]);
+ from.setBit(2);
+ from.setBit(3);
+ EXPECT_EQ(2U, g.addEdges(from, 4, added_edges, kMaxEdges));
+ EXPECT_TRUE(g.hasEdge(2, 4));
+ EXPECT_FALSE(g.hasEdge(2, 5));
+ EXPECT_TRUE(g.hasEdge(3, 4));
+ EXPECT_FALSE(g.hasEdge(3, 5));
+ EXPECT_EQ(2U, added_edges[0]);
+ EXPECT_EQ(3U, added_edges[1]);
+}
+
+TEST(BVGraph, AddEdgesTest) {
+ RunAddEdgesTest<BV2>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc
index 608f90487a7b..e08a38c82450 100644
--- a/lib/sanitizer_common/tests/sanitizer_common_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc
@@ -15,6 +15,9 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_platform.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
namespace __sanitizer {
@@ -113,6 +116,9 @@ TEST(SanitizerCommon, InternalMmapVector) {
vector.pop_back();
EXPECT_EQ((uptr)i, vector.size());
}
+ InternalMmapVector<uptr> empty_vector(0);
+ CHECK_GT(empty_vector.capacity(), 0U);
+ CHECK_EQ(0U, empty_vector.size());
}
void TestThreadInfo(bool main) {
@@ -156,8 +162,8 @@ TEST(SanitizerCommon, ThreadStackTlsMain) {
TEST(SanitizerCommon, ThreadStackTlsWorker) {
InitTlsSize();
pthread_t t;
- pthread_create(&t, 0, WorkerThread, 0);
- pthread_join(t, 0);
+ PTHREAD_CREATE(&t, 0, WorkerThread, 0);
+ PTHREAD_JOIN(t, 0);
}
bool UptrLess(uptr a, uptr b) {
@@ -220,40 +226,4 @@ TEST(SanitizerCommon, InternalScopedString) {
EXPECT_STREQ("012345678", str.data());
}
-TEST(SanitizerCommon, PrintSourceLocation) {
- InternalScopedString str(128);
- PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
- EXPECT_STREQ("/dir/file.cc:10:5", str.data());
-
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 11, 0);
- EXPECT_STREQ("/dir/file.cc:11", str.data());
-
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 0, 0);
- EXPECT_STREQ("/dir/file.cc", str.data());
-
- // Check that we strip file prefix if necessary.
- const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
- common_flags()->strip_path_prefix = "/dir/";
- str.clear();
- PrintSourceLocation(&str, "/dir/file.cc", 10, 5);
- EXPECT_STREQ("file.cc:10:5", str.data());
- common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
-TEST(SanitizerCommon, PrintModuleAndOffset) {
- InternalScopedString str(128);
- PrintModuleAndOffset(&str, "/dir/exe", 0x123);
- EXPECT_STREQ("(/dir/exe+0x123)", str.data());
-
- // Check that we strip file prefix if necessary.
- const char *old_strip_path_prefix = common_flags()->strip_path_prefix;
- common_flags()->strip_path_prefix = "/dir/";
- str.clear();
- PrintModuleAndOffset(&str, "/dir/exe", 0x123);
- EXPECT_STREQ("(exe+0x123)", str.data());
- common_flags()->strip_path_prefix = old_strip_path_prefix;
-}
-
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
new file mode 100644
index 000000000000..8c8363353507
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_deadlock_detector_test.cc
@@ -0,0 +1,496 @@
+//===-- sanitizer_deadlock_detector_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 Sanitizer runtime.
+// Tests for sanitizer_deadlock_detector.h
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_deadlock_detector.h"
+
+#include "sanitizer_test_utils.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+
+using namespace __sanitizer;
+using namespace std;
+
+typedef BasicBitVector<u8> BV1;
+typedef BasicBitVector<> BV2;
+typedef TwoLevelBitVector<> BV3;
+typedef TwoLevelBitVector<3, BasicBitVector<u8> > BV4;
+
+// Poor man's unique_ptr.
+template<class BV>
+struct ScopedDD {
+ ScopedDD() {
+ dp = new DeadlockDetector<BV>;
+ dp->clear();
+ dtls.clear();
+ }
+ ~ScopedDD() { delete dp; }
+ DeadlockDetector<BV> *dp;
+ DeadlockDetectorTLS<BV> dtls;
+};
+
+template <class BV>
+void RunBasicTest() {
+ uptr path[10];
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ set<uptr> s;
+ for (size_t i = 0; i < d.size() * 3; i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+
+ d.clear();
+ s.clear();
+ // Add size() nodes.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_TRUE(s.insert(node).second);
+ }
+ // Remove all nodes.
+ for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it)
+ d.removeNode(*it);
+ // The nodes should be reused.
+ for (size_t i = 0; i < d.size(); i++) {
+ uptr node = d.newNode(0);
+ EXPECT_FALSE(s.insert(node).second);
+ }
+
+ // Cycle: n1->n2->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 1));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_EQ(2U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n2);
+ }
+
+ // Cycle: n1->n2->n3->n1
+ {
+ d.clear();
+ dtls.clear();
+ uptr n1 = d.newNode(1);
+ uptr n2 = d.newNode(2);
+ uptr n3 = d.newNode(3);
+
+ EXPECT_FALSE(d.onLock(&dtls, n1));
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ d.onUnlock(&dtls, n2);
+ d.onUnlock(&dtls, n1);
+
+ EXPECT_FALSE(d.onLock(&dtls, n2));
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ d.onUnlock(&dtls, n3);
+ d.onUnlock(&dtls, n2);
+
+ EXPECT_FALSE(d.onLock(&dtls, n3));
+ EXPECT_EQ(0U, d.findPathToLock(&dtls, n1, path, 2));
+ EXPECT_EQ(3U, d.findPathToLock(&dtls, n1, path, 10));
+ EXPECT_TRUE(d.onLock(&dtls, n1));
+ EXPECT_EQ(path[0], n1);
+ EXPECT_EQ(path[1], n2);
+ EXPECT_EQ(path[2], n3);
+ EXPECT_EQ(d.getData(n1), 1U);
+ EXPECT_EQ(d.getData(n2), 2U);
+ EXPECT_EQ(d.getData(n3), 3U);
+ d.onUnlock(&dtls, n1);
+ d.onUnlock(&dtls, n3);
+ }
+}
+
+TEST(DeadlockDetector, BasicTest) {
+ RunBasicTest<BV1>();
+ RunBasicTest<BV2>();
+ RunBasicTest<BV3>();
+ RunBasicTest<BV4>();
+}
+
+template <class BV>
+void RunRemoveNodeTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(1);
+ uptr l2 = d.newNode(2);
+ uptr l3 = d.newNode(3);
+ uptr l4 = d.newNode(4);
+ uptr l5 = d.newNode(5);
+
+ // l0=>l1=>l2
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onLock(&dtls, l2);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l2);
+ // l3=>l4=>l5
+ d.onLock(&dtls, l3);
+ d.onLock(&dtls, l4);
+ d.onLock(&dtls, l5);
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+ d.onUnlock(&dtls, l5);
+
+ set<uptr> locks;
+ locks.insert(l0);
+ locks.insert(l1);
+ locks.insert(l2);
+ locks.insert(l3);
+ locks.insert(l4);
+ locks.insert(l5);
+ for (uptr i = 6; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ d.onLock(&dtls, lt);
+ d.onUnlock(&dtls, lt);
+ d.removeNode(lt);
+ }
+ EXPECT_EQ(locks.size(), d.size());
+ // l2=>l0
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.onLock(&dtls, l0));
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l0);
+ // l4=>l3
+ EXPECT_FALSE(d.onLock(&dtls, l4));
+ EXPECT_TRUE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l4);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+
+ d.removeNode(l2);
+ d.removeNode(l3);
+ locks.clear();
+ // make sure no edges from or to l0,l1,l4,l5 left.
+ for (uptr i = 4; i < d.size(); i++) {
+ uptr lt = d.newNode(i);
+ locks.insert(lt);
+ uptr a, b;
+ // l0 => lt?
+ a = l0; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // l1 => lt?
+ a = l1; b = lt;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l4?
+ a = lt; b = l4;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+ // lt => l5?
+ a = lt; b = l5;
+ EXPECT_FALSE(d.onLock(&dtls, a));
+ EXPECT_FALSE(d.onLock(&dtls, b));
+ d.onUnlock(&dtls, a);
+ d.onUnlock(&dtls, b);
+
+ d.removeNode(lt);
+ }
+ // Still the same epoch.
+ EXPECT_EQ(d.size(), d.testOnlyGetEpoch());
+ EXPECT_EQ(locks.size(), d.size() - 4);
+ // l2 and l3 should have ben reused.
+ EXPECT_EQ(locks.count(l2), 1U);
+ EXPECT_EQ(locks.count(l3), 1U);
+}
+
+TEST(DeadlockDetector, RemoveNodeTest) {
+ RunRemoveNodeTest<BV1>();
+ RunRemoveNodeTest<BV2>();
+ RunRemoveNodeTest<BV3>();
+ RunRemoveNodeTest<BV4>();
+}
+
+template <class BV>
+void RunMultipleEpochsTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ set<uptr> locks;
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ }
+ locks.clear();
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), 3 * d.size());
+ for (uptr i = 0; i < d.size(); i++) {
+ EXPECT_TRUE(locks.insert(d.newNode(i)).second);
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), 4 * d.size());
+
+#if TSAN_DEBUG == 0
+ // EXPECT_DEATH clones a thread with 4K stack,
+ // which is overflown by tsan memory accesses functions in debug mode.
+
+ // Can not handle the locks from the previous epoch.
+ // The caller should update the lock id.
+ EXPECT_DEATH(d.onLock(&dtls, l0), "CHECK failed.*current_epoch_");
+#endif
+}
+
+TEST(DeadlockDetector, MultipleEpochsTest) {
+ RunMultipleEpochsTest<BV1>();
+ RunMultipleEpochsTest<BV2>();
+ RunMultipleEpochsTest<BV3>();
+ RunMultipleEpochsTest<BV4>();
+}
+
+template <class BV>
+void RunCorrectEpochFlush() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ d.onLock(&dtls, locks1[3]);
+ d.onLock(&dtls, locks1[4]);
+ d.onLock(&dtls, locks1[5]);
+
+ // We have a new epoch, old locks in dtls will have to be forgotten.
+ uptr l0 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ uptr l1 = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size() * 2);
+ d.onLock(&dtls, l0);
+ d.onLock(&dtls, l1);
+ EXPECT_TRUE(d.testOnlyHasEdgeRaw(0, 1));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(1, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(3, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(4, 0));
+ EXPECT_FALSE(d.testOnlyHasEdgeRaw(5, 0));
+}
+
+TEST(DeadlockDetector, CorrectEpochFlush) {
+ RunCorrectEpochFlush<BV1>();
+ RunCorrectEpochFlush<BV2>();
+}
+
+template <class BV>
+void RunTryLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onTryLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ EXPECT_TRUE(d.isHeld(&dtls, l0));
+ EXPECT_TRUE(d.isHeld(&dtls, l1));
+ EXPECT_TRUE(d.isHeld(&dtls, l2));
+ EXPECT_FALSE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l1, l2));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+}
+
+TEST(DeadlockDetector, TryLockTest) {
+ RunTryLockTest<BV1>();
+ RunTryLockTest<BV2>();
+}
+
+template <class BV>
+void RunOnFirstLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // dtls has old epoch.
+ d.onLock(&dtls, l0);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok, same ecpoch, first lock.
+ EXPECT_FALSE(d.onFirstLock(&dtls, l1)); // Second lock.
+ d.onLock(&dtls, l1);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l0);
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Ok
+ d.onUnlock(&dtls, l0);
+
+ vector<uptr> locks1;
+ for (uptr i = 0; i < d.size(); i++)
+ locks1.push_back(d.newNode(i));
+
+ EXPECT_TRUE(d.onFirstLock(&dtls, l0)); // Epoch has changed, but not in dtls.
+
+ uptr l3 = d.newNode(0);
+ d.onLock(&dtls, l3);
+ d.onUnlock(&dtls, l3);
+
+ EXPECT_FALSE(d.onFirstLock(&dtls, l0)); // Epoch has changed in dtls.
+}
+
+TEST(DeadlockDetector, onFirstLockTest) {
+ RunOnFirstLockTest<BV2>();
+}
+
+template <class BV>
+void RunRecusriveLockTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+
+ EXPECT_FALSE(d.onLock(&dtls, l0));
+ EXPECT_FALSE(d.onLock(&dtls, l1));
+ EXPECT_FALSE(d.onLock(&dtls, l0)); // Recurisve.
+ EXPECT_FALSE(d.onLock(&dtls, l2));
+ d.onUnlock(&dtls, l0);
+ EXPECT_FALSE(d.onLock(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ d.onUnlock(&dtls, l1);
+ d.onUnlock(&dtls, l2);
+ d.onUnlock(&dtls, l3);
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l1));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l2));
+ EXPECT_TRUE(d.testOnlyHasEdge(l0, l3));
+}
+
+TEST(DeadlockDetector, RecusriveLockTest) {
+ RunRecusriveLockTest<BV2>();
+}
+
+template <class BV>
+void RunLockContextTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+
+ uptr l0 = d.newNode(0);
+ uptr l1 = d.newNode(0);
+ uptr l2 = d.newNode(0);
+ uptr l3 = d.newNode(0);
+ uptr l4 = d.newNode(0);
+ EXPECT_FALSE(d.onLock(&dtls, l0, 10));
+ EXPECT_FALSE(d.onLock(&dtls, l1, 11));
+ EXPECT_FALSE(d.onLock(&dtls, l2, 12));
+ EXPECT_FALSE(d.onLock(&dtls, l3, 13));
+ EXPECT_EQ(10U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l0);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(12U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+ d.onUnlock(&dtls, l2);
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l0));
+ EXPECT_EQ(11U, d.findLockContext(&dtls, l1));
+ EXPECT_EQ(0U, d.findLockContext(&dtls, l2));
+ EXPECT_EQ(13U, d.findLockContext(&dtls, l3));
+
+ EXPECT_FALSE(d.onLock(&dtls, l4, 14));
+ EXPECT_EQ(14U, d.findLockContext(&dtls, l4));
+}
+
+TEST(DeadlockDetector, LockContextTest) {
+ RunLockContextTest<BV2>();
+}
+
+template <class BV>
+void RunRemoveEdgesTest() {
+ ScopedDD<BV> sdd;
+ DeadlockDetector<BV> &d = *sdd.dp;
+ DeadlockDetectorTLS<BV> &dtls = sdd.dtls;
+ vector<uptr> node(BV::kSize);
+ u32 stk_from = 0, stk_to = 0;
+ int unique_tid = 0;
+ for (size_t i = 0; i < BV::kSize; i++)
+ node[i] = d.newNode(0);
+
+ for (size_t i = 0; i < BV::kSize; i++)
+ EXPECT_FALSE(d.onLock(&dtls, node[i], i + 1));
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ EXPECT_EQ(stk_from, i + 1);
+ EXPECT_EQ(stk_to, j + 1);
+ }
+ }
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // Remove and re-create half of the nodes.
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ d.removeNode(node[i]);
+ for (uptr i = 1; i < BV::kSize; i += 2)
+ node[i] = d.newNode(0);
+ EXPECT_EQ(d.testOnlyGetEpoch(), d.size());
+ // The edges from or to the removed nodes should be gone.
+ for (size_t i = 0; i < BV::kSize; i++) {
+ for (uptr j = i + 1; j < BV::kSize; j++) {
+ if ((i % 2) || (j % 2))
+ EXPECT_FALSE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ else
+ EXPECT_TRUE(
+ d.findEdge(node[i], node[j], &stk_from, &stk_to, &unique_tid));
+ }
+ }
+}
+
+TEST(DeadlockDetector, RemoveEdgesTest) {
+ RunRemoveEdgesTest<BV1>();
+}
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
index cd3cac11bc80..1055f5d24d6b 100644
--- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -24,14 +24,14 @@ static const char kFlagName[] = "flag_name";
template <typename T>
static void TestFlag(T start_value, const char *env, T final_value) {
T flag = start_value;
- ParseFlag(env, &flag, kFlagName);
+ ParseFlag(env, &flag, kFlagName, "flag description");
EXPECT_EQ(final_value, flag);
}
static void TestStrFlag(const char *start_value, const char *env,
const char *final_value) {
const char *flag = start_value;
- ParseFlag(env, &flag, kFlagName);
+ ParseFlag(env, &flag, kFlagName, "flag description");
EXPECT_EQ(0, internal_strcmp(final_value, flag));
}
@@ -49,7 +49,7 @@ TEST(SanitizerCommon, BooleanFlags) {
TEST(SanitizerCommon, IntFlags) {
TestFlag(-11, 0, -11);
- TestFlag(-11, "flag_name", 0);
+ TestFlag(-11, "flag_name", -11);
TestFlag(-11, "--flag_name=", 0);
TestFlag(-11, "--flag_name=42", 42);
TestFlag(-11, "--flag_name=-42", -42);
@@ -57,7 +57,7 @@ TEST(SanitizerCommon, IntFlags) {
TEST(SanitizerCommon, StrFlags) {
TestStrFlag("zzz", 0, "zzz");
- TestStrFlag("zzz", "flag_name", "");
+ TestStrFlag("zzz", "flag_name", "zzz");
TestStrFlag("zzz", "--flag_name=", "");
TestStrFlag("", "--flag_name=abc", "abc");
TestStrFlag("", "--flag_name='abc zxc'", "abc zxc");
@@ -70,8 +70,8 @@ static void TestTwoFlags(const char *env, bool expected_flag1,
const char *expected_flag2) {
bool flag1 = !expected_flag1;
const char *flag2 = "";
- ParseFlag(env, &flag1, "flag1");
- ParseFlag(env, &flag2, "flag2");
+ ParseFlag(env, &flag1, "flag1", "flag1 description");
+ ParseFlag(env, &flag2, "flag2", "flag2 description");
EXPECT_EQ(expected_flag1, flag1);
EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
}
diff --git a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
index e0354062508f..13918aff1009 100644
--- a/lib/sanitizer_common/tests/sanitizer_scanf_interceptor_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cc
@@ -1,4 +1,4 @@
-//===-- sanitizer_scanf_interceptor_test.cc -------------------------------===//
+//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,22 +10,59 @@
// Tests for *scanf interceptors implementation in sanitizer_common.
//
//===----------------------------------------------------------------------===//
+#include <algorithm>
#include <vector>
#include "interception/interception.h"
#include "sanitizer_test_utils.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "gtest/gtest.h"
using namespace __sanitizer;
+#define COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size) \
+ do { \
+ ((std::vector<unsigned> *)ctx)->push_back(size); \
+ ptr = ptr; \
+ } while (0)
+
+#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
- ((std::vector<unsigned> *)ctx)->push_back(size)
+ COMMON_INTERCEPTOR_READ_WRITE_RANGE(ctx, ptr, size)
+
+#define SANITIZER_INTERCEPT_PRINTF 1
+#include "sanitizer_common/sanitizer_common_interceptors_format.inc"
+
+static const unsigned I = sizeof(int);
+static const unsigned L = sizeof(long);
+static const unsigned LL = sizeof(long long);
+static const unsigned S = sizeof(short);
+static const unsigned C = sizeof(char);
+static const unsigned LC = sizeof(wchar_t);
+static const unsigned D = sizeof(double);
+static const unsigned LD = sizeof(long double);
+static const unsigned F = sizeof(float);
+static const unsigned P = sizeof(char *);
+
+static void verifyFormatResults(const char *format, unsigned n,
+ const std::vector<unsigned> &computed_sizes,
+ va_list expected_sizes) {
+ // "+ 1" because of format string
+ ASSERT_EQ(n + 1,
+ computed_sizes.size()) << "Unexpected number of format arguments: '"
+ << format << "'";
+ for (unsigned i = 0; i < n; ++i)
+ EXPECT_EQ(va_arg(expected_sizes, unsigned), computed_sizes[i + 1])
+ << "Unexpect write size for argument " << i << ", format string '"
+ << format << "'";
+}
-#include "sanitizer_common/sanitizer_common_interceptors_scanf.inc"
+static const char test_buf[] = "Test string.";
+static const size_t test_buf_size = sizeof(test_buf);
-static const char scanf_buf[] = "Test string.";
-static size_t scanf_buf_size = sizeof(scanf_buf);
static const unsigned SCANF_ARGS_MAX = 16;
static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
@@ -42,15 +79,10 @@ static void testScanf2(const char *format, int scanf_result,
std::vector<unsigned> scanf_sizes;
// 16 args should be enough.
testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, format,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf, scanf_buf,
- scanf_buf, scanf_buf, scanf_buf, scanf_buf);
- ASSERT_EQ(n, scanf_sizes.size()) << "Unexpected number of format arguments: '"
- << format << "'";
- for (unsigned i = 0; i < n; ++i)
- EXPECT_EQ(va_arg(expected_sizes, unsigned), scanf_sizes[i])
- << "Unexpect write size for argument " << i << ", format string '"
- << format << "'";
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, scanf_sizes, expected_sizes);
}
static void testScanf(const char *format, unsigned n, ...) {
@@ -76,23 +108,15 @@ static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
}
TEST(SanitizerCommonInterceptors, Scanf) {
- const unsigned I = sizeof(int); // NOLINT
- const unsigned L = sizeof(long); // NOLINT
- const unsigned LL = sizeof(long long); // NOLINT
- const unsigned S = sizeof(short); // NOLINT
- const unsigned C = sizeof(char); // NOLINT
- const unsigned D = sizeof(double); // NOLINT
- const unsigned LD = sizeof(long double); // NOLINT
- const unsigned F = sizeof(float); // NOLINT
- const unsigned P = sizeof(char *); // NOLINT
-
testScanf("%d", 1, I);
testScanf("%d%d%d", 3, I, I, I);
testScanf("ab%u%dc", 2, I, I);
testScanf("%ld", 1, L);
testScanf("%llu", 1, LL);
+ testScanf("%qd", 1, LL);
testScanf("a %hd%hhx", 2, S, C);
testScanf("%c", 1, C);
+ testScanf("%lc", 1, LC);
testScanf("%%", 0);
testScanf("a%%", 0);
@@ -108,15 +132,17 @@ TEST(SanitizerCommonInterceptors, Scanf) {
testScanf("%10s", 1, 11);
testScanf("%10c", 1, 10);
+ testScanf("%10ls", 1, 11 * LC);
+ testScanf("%10lc", 1, 10 * LC);
testScanf("%%10s", 0);
testScanf("%*10s", 0);
testScanf("%*d", 0);
testScanf("%4d%8f%c", 3, I, F, C);
- testScanf("%s%d", 2, scanf_buf_size, I);
- testScanf("%[abc]", 1, scanf_buf_size);
+ testScanf("%s%d", 2, test_buf_size, I);
+ testScanf("%[abc]", 1, test_buf_size);
testScanf("%4[bcdef]", 1, 5);
- testScanf("%[]]", 1, scanf_buf_size);
+ testScanf("%[]]", 1, test_buf_size);
testScanf("%8[^]%d0-9-]%c", 2, 9, C);
testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
@@ -172,7 +198,62 @@ TEST(SanitizerCommonInterceptors, Scanf) {
testScanfPartial("%d%n%n%d //1\n", 1, 3, I, I, I);
testScanfPartial("%d%n%n%d //2\n", 2, 4, I, I, I, I);
- testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, scanf_buf_size);
- testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, scanf_buf_size,
- scanf_buf_size);
+ testScanfPartial("%d%n%n%d %s %s", 3, 5, I, I, I, I, test_buf_size);
+ testScanfPartial("%d%n%n%d %s %s", 4, 6, I, I, I, I, test_buf_size,
+ test_buf_size);
+}
+
+static void testPrintf3(void *ctx, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ printf_common(ctx, format, ap);
+ va_end(ap);
+}
+
+static void testPrintf2(const char *format, unsigned n,
+ va_list expected_sizes) {
+ std::vector<unsigned> printf_sizes;
+ // 16 args should be enough.
+ testPrintf3((void *)&printf_sizes, format,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf, test_buf, test_buf,
+ test_buf, test_buf, test_buf, test_buf);
+ verifyFormatResults(format, n, printf_sizes, expected_sizes);
+}
+
+static void testPrintf(const char *format, unsigned n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ testPrintf2(format, n, ap);
+ va_end(ap);
+}
+
+TEST(SanitizerCommonInterceptors, Printf) {
+ // Only test functionality which differs from scanf
+
+ // Indexed arguments
+ testPrintf("%5$d", 0);
+ testPrintf("%.*5$d", 0);
+
+ // errno
+ testPrintf("%0-m", 0);
+
+ // Dynamic width
+ testPrintf("%*n", 1, I);
+ testPrintf("%*.10n", 1, I);
+
+ // Precision
+ testPrintf("%10.10n", 1, I);
+ testPrintf("%.3s", 1, 3);
+ testPrintf("%.20s", 1, test_buf_size);
+
+ // Dynamic precision
+ testPrintf("%.*n", 1, I);
+ testPrintf("%10.*n", 1, I);
+
+ // Dynamic precision for strings is not implemented yet.
+ testPrintf("%.*s", 1, 0);
+
+ // Checks for wide-character strings are not implemented yet.
+ testPrintf("%ls", 1, 0);
}
diff --git a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
index 154d9860b79f..22fa5228dfbd 100644
--- a/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc
@@ -47,6 +47,7 @@ static struct IoctlInit {
// Avoid unused function warnings.
(void)&ioctl_common_pre;
(void)&ioctl_common_post;
+ (void)&ioctl_decode;
}
} ioctl_static_initializer;
@@ -74,4 +75,29 @@ TEST(SanitizerIoctl, Fixup) {
EXPECT_EQ(EVIOCGKEY(0), desc->req);
}
+// Test decoding KVM ioctl numbers.
+TEST(SanitizerIoctl, KVM_GET_MP_STATE) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8004ae98U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_LAPIC) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0x8400ae8eU, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::WRITE, desc.type);
+ EXPECT_EQ(1024U, desc.size);
+}
+
+TEST(SanitizerIoctl, KVM_GET_MSR_INDEX_LIST) {
+ ioctl_desc desc;
+ bool res = ioctl_decode(0xc004ae02U, &desc);
+ EXPECT_TRUE(res);
+ EXPECT_EQ(ioctl_desc::READWRITE, desc.type);
+ EXPECT_EQ(4U, desc.size);
+}
+
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
index c4f3d8033c2d..660710d5bb7e 100644
--- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc
@@ -55,6 +55,8 @@ struct stat_and_more {
unsigned char z;
};
+// FIXME: File manipulations are not yet supported on Windows
+#if !defined(_WIN32)
TEST(SanitizerCommon, FileOps) {
const char *str1 = "qwerty";
uptr len1 = internal_strlen(str1);
@@ -114,6 +116,7 @@ TEST(SanitizerCommon, FileOps) {
EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
internal_close(fd);
}
+#endif
TEST(SanitizerCommon, InternalStrFunctions) {
const char *haystack = "haystack";
diff --git a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
index 06f742b41796..d14e7c2fba21 100644
--- a/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_mutex_test.cc
@@ -12,6 +12,9 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_common.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
#include <string.h>
@@ -103,9 +106,9 @@ TEST(SanitizerCommon, SpinMutex) {
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, lock_thread<SpinMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, SpinMutexTry) {
@@ -114,9 +117,9 @@ TEST(SanitizerCommon, SpinMutexTry) {
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, try_thread<SpinMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, BlockingMutex) {
@@ -125,9 +128,9 @@ TEST(SanitizerCommon, BlockingMutex) {
TestData<BlockingMutex> data(mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
- pthread_create(&threads[i], 0, lock_thread<BlockingMutex>, &data);
+ PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
for (int i = 0; i < kThreads; i++)
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
check_locked(mtx);
}
diff --git a/lib/sanitizer_common/tests/sanitizer_posix_test.cc b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
index 035899c83022..56ce416141fa 100644
--- a/lib/sanitizer_common/tests/sanitizer_posix_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_posix_test.cc
@@ -18,6 +18,7 @@
#include "gtest/gtest.h"
#include <pthread.h>
+#include <sys/mman.h>
namespace __sanitizer {
@@ -57,6 +58,23 @@ TEST(SanitizerCommon, PthreadDestructorIterations) {
EXPECT_FALSE(destructor_executed);
}
+TEST(SanitizerCommon, IsAccessibleMemoryRange) {
+ const int page_size = GetPageSize();
+ uptr mem = (uptr)mmap(0, 3 * page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ // Protect the middle page.
+ mprotect((void *)(mem + page_size), page_size, PROT_NONE);
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1));
+ EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size));
+ EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2));
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/lib/sanitizer_common/tests/sanitizer_printf_test.cc b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
index 2c478cc74286..d0b46ac94ff2 100644
--- a/lib/sanitizer_common/tests/sanitizer_printf_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_printf_test.cc
@@ -103,6 +103,11 @@ TEST(Printf, OverflowPtr) {
EXPECT_EQ(buf[9], 0);
}
+#if defined(_WIN32)
+// Oh well, MSVS headers don't define snprintf.
+# define snprintf _snprintf
+#endif
+
template<typename T>
static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
char buf[1024];
@@ -115,12 +120,14 @@ static void TestAgainstLibc(const char *fmt, T arg1, T arg2) {
TEST(Printf, MinMax) {
TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
- TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
TestAgainstLibc<unsigned>("%u-%u", 0, UINT_MAX); // NOLINT
- TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
TestAgainstLibc<unsigned>("%x-%x", 0, UINT_MAX); // NOLINT
+#if !defined(_WIN32)
+ // %z* format doesn't seem to be supported by MSVS.
+ TestAgainstLibc<long>("%zd-%zd", LONG_MIN, LONG_MAX); // NOLINT
+ TestAgainstLibc<unsigned long>("%zu-%zu", 0, ULONG_MAX); // NOLINT
TestAgainstLibc<unsigned long>("%zx-%zx", 0, ULONG_MAX); // NOLINT
- Report("%zd\n", LONG_MIN);
+#endif
}
TEST(Printf, Padding) {
@@ -136,4 +143,14 @@ TEST(Printf, Padding) {
TestAgainstLibc<int>("%03d - %03d", -12, -1234);
}
+TEST(Printf, Precision) {
+ char buf[1024];
+ uptr len = internal_snprintf(buf, sizeof(buf), "%.*s", 3, "12345");
+ EXPECT_EQ(3U, len);
+ EXPECT_STREQ("123", buf);
+ len = internal_snprintf(buf, sizeof(buf), "%.*s", 6, "12345");
+ EXPECT_EQ(5U, len);
+ EXPECT_STREQ("12345", buf);
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
index d16e2eebf98e..495b726dcc45 100644
--- a/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_procmaps_test.cc
@@ -10,21 +10,48 @@
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
+#if !defined(_WIN32) // There are no /proc/maps on Windows.
+
#include "sanitizer_common/sanitizer_procmaps.h"
-//#include "sanitizer_common/sanitizer_internal_defs.h"
-//#include "sanitizer_common/sanitizer_libc.h"
#include "gtest/gtest.h"
+#include <stdlib.h>
+
+static void noop() {}
+extern const char *argv0;
+
namespace __sanitizer {
-#ifdef SANITIZER_LINUX
-TEST(ProcMaps, CodeRange) {
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+TEST(MemoryMappingLayout, CodeRange) {
uptr start, end;
bool res = GetCodeRangeForFile("[vdso]", &start, &end);
EXPECT_EQ(res, true);
- EXPECT_GT(start, (uptr)0);
+ EXPECT_GT(start, 0U);
EXPECT_LT(start, end);
}
#endif
+TEST(MemoryMappingLayout, DumpListOfModules) {
+ const char *last_slash = strrchr(argv0, '/');
+ const char *binary_name = last_slash ? last_slash + 1 : argv0;
+ MemoryMappingLayout memory_mapping(false);
+ const uptr kMaxModules = 100;
+ LoadedModule *modules =
+ (LoadedModule *)malloc(kMaxModules * sizeof(LoadedModule));
+ uptr n_modules = memory_mapping.DumpListOfModules(modules, kMaxModules, 0);
+ EXPECT_GT(n_modules, 0U);
+ bool found = false;
+ for (uptr i = 0; i < n_modules; ++i) {
+ if (modules[i].containsAddress((uptr)&noop)) {
+ // Verify that the module name is sane.
+ if (strstr(modules[i].full_name(), binary_name) != 0)
+ found = true;
+ }
+ }
+ EXPECT_TRUE(found);
+ free(modules);
+}
+
} // namespace __sanitizer
+#endif // !defined(_WIN32)
diff --git a/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
new file mode 100644
index 000000000000..47b0f97de840
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_pthread_wrappers.h
@@ -0,0 +1,66 @@
+//===-- sanitizer_pthread_wrappers.h ----------------------------*- C++ -*-===//
+//
+// 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 *Sanitizer runtime.
+// It provides handy wrappers for thread manipulation, that:
+// a) assert on any failure rather than returning an error code
+// b) defines pthread-like interface on platforms where where <pthread.h>
+// is not supplied by default.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PTHREAD_WRAPPERS_H
+#define SANITIZER_PTHREAD_WRAPPERS_H
+
+#include "sanitizer_test_utils.h"
+
+#if !defined(_WIN32)
+# include <pthread.h>
+// Simply forward the arguments and check that the pthread functions succeed.
+# define PTHREAD_CREATE(a, b, c, d) ASSERT_EQ(0, pthread_create(a, b, c, d))
+# define PTHREAD_JOIN(a, b) ASSERT_EQ(0, pthread_join(a, b))
+#else
+typedef HANDLE pthread_t;
+
+struct PthreadHelperCreateThreadInfo {
+ void *(*start_routine)(void *);
+ void *arg;
+};
+
+inline DWORD WINAPI PthreadHelperThreadProc(void *arg) {
+ PthreadHelperCreateThreadInfo *start_data =
+ reinterpret_cast<PthreadHelperCreateThreadInfo*>(arg);
+ void *ret = (start_data->start_routine)(start_data->arg);
+ delete start_data;
+ return (DWORD)ret;
+}
+
+inline void PTHREAD_CREATE(pthread_t *thread, void *attr,
+ void *(*start_routine)(void *), void *arg) {
+ ASSERT_EQ(0, attr) << "Thread attributes are not supported yet.";
+ PthreadHelperCreateThreadInfo *data = new PthreadHelperCreateThreadInfo;
+ data->start_routine = start_routine;
+ data->arg = arg;
+ *thread = CreateThread(0, 0, PthreadHelperThreadProc, data, 0, 0);
+ ASSERT_NE(nullptr, *thread) << "Failed to create a thread.";
+}
+
+inline void PTHREAD_JOIN(pthread_t thread, void **value_ptr) {
+ ASSERT_EQ(0, value_ptr) << "Nonzero value_ptr is not supported yet.";
+ ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+ ASSERT_NE(0, CloseHandle(thread));
+}
+
+inline void pthread_exit(void *retval) {
+ ASSERT_EQ(0, retval) << "Nonzero retval is not supported yet.";
+ ExitThread((DWORD)retval);
+}
+#endif // _WIN32
+
+#endif // SANITIZER_PTHREAD_WRAPPERS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
index 5c075d53ebff..513432fac214 100644
--- a/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cc
@@ -18,74 +18,75 @@
namespace __sanitizer {
TEST(SanitizerCommon, StackDepotBasic) {
- uptr s1[] = {1, 2, 3, 4, 5};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_NE(sp1, (uptr*)0);
- EXPECT_EQ(sz1, ARRAY_SIZE(s1));
- EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+ uptr array[] = {1, 2, 3, 4, 5};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
}
TEST(SanitizerCommon, StackDepotAbsent) {
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet((1 << 30) - 1, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ StackTrace stack = StackDepotGet((1 << 30) - 1);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotEmptyStack) {
- u32 i1 = StackDepotPut(0, 0);
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ u32 i1 = StackDepotPut(StackTrace());
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotZeroId) {
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(0, &sz1);
- EXPECT_EQ(sp1, (uptr*)0);
+ StackTrace stack = StackDepotGet(0);
+ EXPECT_EQ((uptr*)0, stack.trace);
}
TEST(SanitizerCommon, StackDepotSame) {
- uptr s1[] = {1, 2, 3, 4, 6};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- u32 i2 = StackDepotPut(s1, ARRAY_SIZE(s1));
+ uptr array[] = {1, 2, 3, 4, 6};
+ StackTrace s1(array, ARRAY_SIZE(array));
+ u32 i1 = StackDepotPut(s1);
+ u32 i2 = StackDepotPut(s1);
EXPECT_EQ(i1, i2);
- uptr sz1 = 0;
- const uptr *sp1 = StackDepotGet(i1, &sz1);
- EXPECT_NE(sp1, (uptr*)0);
- EXPECT_EQ(sz1, ARRAY_SIZE(s1));
- EXPECT_EQ(internal_memcmp(sp1, s1, sizeof(s1)), 0);
+ StackTrace stack = StackDepotGet(i1);
+ EXPECT_NE(stack.trace, (uptr*)0);
+ EXPECT_EQ(ARRAY_SIZE(array), stack.size);
+ EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));
}
TEST(SanitizerCommon, StackDepotSeveral) {
- uptr s1[] = {1, 2, 3, 4, 7};
- u32 i1 = StackDepotPut(s1, ARRAY_SIZE(s1));
- uptr s2[] = {1, 2, 3, 4, 8, 9};
- u32 i2 = StackDepotPut(s2, ARRAY_SIZE(s2));
+ uptr array1[] = {1, 2, 3, 4, 7};
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ u32 i1 = StackDepotPut(s1);
+ uptr array2[] = {1, 2, 3, 4, 8, 9};
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ u32 i2 = StackDepotPut(s2);
EXPECT_NE(i1, i2);
}
TEST(SanitizerCommon, StackDepotReverseMap) {
- uptr s1[] = {1, 2, 3, 4, 5};
- uptr s2[] = {7, 1, 3, 0};
- uptr s3[] = {10, 2, 5, 3};
- uptr s4[] = {1, 3, 2, 5};
+ uptr array1[] = {1, 2, 3, 4, 5};
+ uptr array2[] = {7, 1, 3, 0};
+ uptr array3[] = {10, 2, 5, 3};
+ uptr array4[] = {1, 3, 2, 5};
u32 ids[4] = {0};
- ids[0] = StackDepotPut(s1, ARRAY_SIZE(s1));
- ids[1] = StackDepotPut(s2, ARRAY_SIZE(s2));
- ids[2] = StackDepotPut(s3, ARRAY_SIZE(s3));
- ids[3] = StackDepotPut(s4, ARRAY_SIZE(s4));
+ StackTrace s1(array1, ARRAY_SIZE(array1));
+ StackTrace s2(array2, ARRAY_SIZE(array2));
+ StackTrace s3(array3, ARRAY_SIZE(array3));
+ StackTrace s4(array4, ARRAY_SIZE(array4));
+ ids[0] = StackDepotPut(s1);
+ ids[1] = StackDepotPut(s2);
+ ids[2] = StackDepotPut(s3);
+ ids[3] = StackDepotPut(s4);
StackDepotReverseMap map;
for (uptr i = 0; i < 4; i++) {
- uptr sz_depot, sz_map;
- const uptr *sp_depot, *sp_map;
- sp_depot = StackDepotGet(ids[i], &sz_depot);
- sp_map = map.Get(ids[i], &sz_map);
- EXPECT_EQ(sz_depot, sz_map);
- EXPECT_EQ(sp_depot, sp_map);
+ StackTrace stack = StackDepotGet(ids[i]);
+ StackTrace from_map = map.Get(ids[i]);
+ EXPECT_EQ(stack.size, from_map.size);
+ EXPECT_EQ(stack.trace, from_map.trace);
}
}
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
new file mode 100644
index 000000000000..cc9a9edbbb46
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_printer_test.cc
@@ -0,0 +1,122 @@
+//===-- sanitizer_common_printer_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 sanitizer_common test suite.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
+
+#include "gtest/gtest.h"
+
+namespace __sanitizer {
+
+TEST(SanitizerStacktracePrinter, RenderSourceLocation) {
+ InternalScopedString str(128);
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "");
+ EXPECT_STREQ("/dir/file.cc:10:5", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 11, 0, "");
+ EXPECT_STREQ("/dir/file.cc:11", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 0, 0, "");
+ EXPECT_STREQ("/dir/file.cc", str.data());
+
+ str.clear();
+ RenderSourceLocation(&str, "/dir/file.cc", 10, 5, "/dir/");
+ EXPECT_STREQ("file.cc:10:5", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderModuleLocation) {
+ InternalScopedString str(128);
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "");
+ EXPECT_STREQ("(/dir/exe+0x123)", str.data());
+
+ // Check that we strip file prefix if necessary.
+ str.clear();
+ RenderModuleLocation(&str, "/dir/exe", 0x123, "/dir/");
+ EXPECT_STREQ("(exe+0x123)", str.data());
+}
+
+TEST(SanitizerStacktracePrinter, RenderFrame) {
+ int frame_no = 42;
+ AddressInfo info;
+ info.address = 0x400000;
+ info.module = internal_strdup("/path/to/my/module");
+ info.module_offset = 0x200;
+ info.function = internal_strdup("function_foo");
+ info.function_offset = 0x100;
+ info.file = internal_strdup("/path/to/my/source");
+ info.line = 10;
+ info.column = 5;
+ InternalScopedString str(256);
+
+ // Dump all the AddressInfo fields.
+ RenderFrame(&str, "%% Frame:%n PC:%p Module:%m ModuleOffset:%o "
+ "Function:%f FunctionOffset:%q Source:%s Line:%l "
+ "Column:%c",
+ frame_no, info, "/path/to/", "function_");
+ EXPECT_STREQ("% Frame:42 PC:0x400000 Module:my/module ModuleOffset:0x200 "
+ "Function:foo FunctionOffset:0x100 Source:my/source Line:10 "
+ "Column:5",
+ str.data());
+ info.Clear();
+ str.clear();
+
+ // Test special format specifiers.
+ info.address = 0x400000;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "400000"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(<unknown module>)", str.data());
+ str.clear();
+
+ info.module = internal_strdup("/path/to/module");
+ info.module_offset = 0x200;
+ RenderFrame(&str, "%M", frame_no, info);
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "(module+0x"));
+ EXPECT_NE(nullptr, internal_strstr(str.data(), "200"));
+ str.clear();
+
+ RenderFrame(&str, "%L", frame_no, info);
+ EXPECT_STREQ("(/path/to/module+0x200)", str.data());
+ str.clear();
+
+ info.function = internal_strdup("my_function");
+ RenderFrame(&str, "%F", frame_no, info);
+ EXPECT_STREQ("in my_function", str.data());
+ str.clear();
+
+ info.function_offset = 0x100;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function+0x100 <null>", str.data());
+ str.clear();
+
+ info.file = internal_strdup("my_file");
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file", str.data());
+ str.clear();
+
+ info.line = 10;
+ RenderFrame(&str, "%F %S", frame_no, info);
+ EXPECT_STREQ("in my_function my_file:10", str.data());
+ str.clear();
+
+ info.column = 5;
+ RenderFrame(&str, "%S %L", frame_no, info);
+ EXPECT_STREQ("my_file:10:5 my_file:10:5", str.data());
+ str.clear();
+
+ info.Clear();
+}
+
+} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
index 2b842cd8134a..ac820c25a0f8 100644
--- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc
@@ -20,19 +20,22 @@ namespace __sanitizer {
class FastUnwindTest : public ::testing::Test {
protected:
virtual void SetUp();
+ virtual void TearDown();
bool TryFastUnwind(uptr max_depth) {
if (!StackTrace::WillUseFastUnwind(true))
return false;
- trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], fake_top,
+ trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
fake_bottom, true);
return true;
}
- uptr fake_stack[10];
+ void *mapping;
+ uptr *fake_stack;
+ const uptr fake_stack_size = 10;
uptr start_pc;
uptr fake_top;
uptr fake_bottom;
- StackTrace trace;
+ BufferedStackTrace trace;
};
static uptr PC(uptr idx) {
@@ -40,22 +43,34 @@ static uptr PC(uptr idx) {
}
void FastUnwindTest::SetUp() {
+ size_t ps = GetPageSize();
+ mapping = MmapOrDie(2 * ps, "FastUnwindTest");
+ Mprotect((uptr)mapping, ps);
+
+ // Unwinder may peek 1 word down from the starting FP.
+ fake_stack = (uptr *)((uptr)mapping + ps + sizeof(uptr));
+
// Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have
// even indices.
- for (uptr i = 0; i+1 < ARRAY_SIZE(fake_stack); i += 2) {
+ for (uptr i = 0; i + 1 < fake_stack_size; i += 2) {
fake_stack[i] = (uptr)&fake_stack[i+2]; // fp
fake_stack[i+1] = PC(i + 1); // retaddr
}
- // Mark the last fp as zero to terminate the stack trace.
- fake_stack[RoundDownTo(ARRAY_SIZE(fake_stack) - 1, 2)] = 0;
+ // Mark the last fp point back up to terminate the stack trace.
+ fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uptr)&fake_stack[0];
// Top is two slots past the end because FastUnwindStack subtracts two.
- fake_top = (uptr)&fake_stack[ARRAY_SIZE(fake_stack) + 2];
+ fake_top = (uptr)&fake_stack[fake_stack_size + 2];
// Bottom is one slot before the start because FastUnwindStack uses >.
- fake_bottom = (uptr)&fake_stack[-1];
+ fake_bottom = (uptr)mapping;
start_pc = PC(0);
}
+void FastUnwindTest::TearDown() {
+ size_t ps = GetPageSize();
+ UnmapOrDie(mapping, 2 * ps);
+}
+
TEST_F(FastUnwindTest, Basic) {
if (!TryFastUnwind(kStackTraceMax))
return;
@@ -102,4 +117,38 @@ TEST_F(FastUnwindTest, OneFrameStackTrace) {
EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
}
+TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
+ if (!TryFastUnwind(0))
+ return;
+ EXPECT_EQ(0U, trace.size);
+ EXPECT_EQ(0U, trace.top_frame_bp);
+}
+
+TEST_F(FastUnwindTest, FPBelowPrevFP) {
+ // The next FP points to unreadable memory inside the stack limits, but below
+ // current FP.
+ fake_stack[0] = (uptr)&fake_stack[-50];
+ fake_stack[1] = PC(1);
+ if (!TryFastUnwind(3))
+ return;
+ EXPECT_EQ(2U, trace.size);
+ EXPECT_EQ(PC(0), trace.trace[0]);
+ EXPECT_EQ(PC(1), trace.trace[1]);
+}
+
+TEST(SlowUnwindTest, ShortStackTrace) {
+ if (StackTrace::WillUseFastUnwind(false))
+ return;
+ BufferedStackTrace stack;
+ uptr pc = StackTrace::GetCurrentPc();
+ uptr bp = GET_CURRENT_FRAME();
+ stack.Unwind(0, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(0U, stack.size);
+ EXPECT_EQ(0U, stack.top_frame_bp);
+ stack.Unwind(1, pc, bp, 0, 0, 0, false);
+ EXPECT_EQ(1U, stack.size);
+ EXPECT_EQ(pc, stack.trace[0]);
+ EXPECT_EQ(bp, stack.top_frame_bp);
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index ea8741d4f01a..0699243283df 100644
--- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -66,9 +66,21 @@ TEST(Suppressions, TypeStrings) {
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
- "called_from_lib"));
+ "called_from_lib"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
+ "vptr_check"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionInterceptorName),
+ "interceptor_name"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaFunction),
+ "interceptor_via_fun"));
+ CHECK(
+ !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaLibrary),
+ "interceptor_via_lib"));
// Ensure this test is up-to-date when suppression types are added.
- CHECK_EQ(SuppressionTypeCount, 7);
+ CHECK_EQ(12, SuppressionTypeCount);
}
class SuppressionContextTest : public ::testing::Test {
@@ -149,4 +161,14 @@ TEST_F(SuppressionContextTest, ParseType) {
EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
}
+TEST_F(SuppressionContextTest, HasSuppressionType) {
+ ctx_->Parse(
+ "race:foo\n"
+ "thread:bar\n");
+ EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionRace));
+ EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionThread));
+ EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionMutex));
+ EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionSignal));
+}
+
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/tests/sanitizer_test_config.h b/lib/sanitizer_common/tests/sanitizer_test_config.h
new file mode 100644
index 000000000000..bdf614606d6a
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_test_config.h
@@ -0,0 +1,30 @@
+//===-- sanitizer_test_config.h ---------------------------------*- C++ -*-===//
+//
+// 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 *Sanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_SANITIZER_TEST_UTILS_H)
+# error "This file should be included into sanitizer_test_utils.h only"
+#endif
+
+#ifndef SANITIZER_TEST_CONFIG_H
+#define SANITIZER_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#if SANITIZER_USE_DEJAGNU_GTEST
+# include "dejagnu-gtest.h"
+#else
+# include "gtest/gtest.h"
+#endif
+
+#endif // SANITIZER_TEST_CONFIG_H
diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h
index 17adb2647656..64db37f341d3 100644
--- a/lib/sanitizer_common/tests/sanitizer_test_utils.h
+++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h
@@ -16,21 +16,34 @@
#define SANITIZER_TEST_UTILS_H
#if defined(_WIN32)
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-typedef __int8 int8_t;
-typedef __int16 int16_t;
-typedef __int32 int32_t;
-typedef __int64 int64_t;
+// <windows.h> should always be the first include on Windows.
+# include <windows.h>
+// MSVS headers define max/min as macros, so std::max/min gets crazy.
+# undef max
+# undef min
+#endif
+
+#if !defined(SANITIZER_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+# include "sanitizer_test_config.h"
+# undef INCLUDED_FROM_SANITIZER_TEST_UTILS_H
+#endif
+
+#include <stdint.h>
+
+#if defined(_MSC_VER)
# define NOINLINE __declspec(noinline)
-# define USED
-#else // defined(_WIN32)
+#else // defined(_MSC_VER)
# define NOINLINE __attribute__((noinline))
+#endif // defined(_MSC_VER)
+
+#if !defined(_MSC_VER) || defined(__clang__)
+# define UNUSED __attribute__((unused))
# define USED __attribute__((used))
-#include <stdint.h>
-#endif // defined(_WIN32)
+#else
+# define UNUSED
+# define USED
+#endif
#if !defined(__has_feature)
#define __has_feature(x) 0
@@ -53,7 +66,9 @@ typedef __int64 int64_t;
// Make the compiler thinks that something is going on there.
inline void break_optimization(void *arg) {
+#if !defined(_WIN32) || defined(__clang__)
__asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
}
// This function returns its parameter but in such a way that compiler
@@ -78,5 +93,29 @@ static inline uint32_t my_rand() {
return my_rand_r(&global_seed);
}
+// Set availability of platform-specific functions.
+
+#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 1
+#else
+# define SANITIZER_TEST_HAS_POSIX_MEMALIGN 0
+#endif
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
+ !defined(__ANDROID__) && !defined(_WIN32)
+# define SANITIZER_TEST_HAS_MEMALIGN 1
+# define SANITIZER_TEST_HAS_PVALLOC 1
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 1
+#else
+# define SANITIZER_TEST_HAS_MEMALIGN 0
+# define SANITIZER_TEST_HAS_PVALLOC 0
+# define SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE 0
+#endif
+
+#if !defined(__APPLE__)
+# define SANITIZER_TEST_HAS_STRNLEN 1
+#else
+# define SANITIZER_TEST_HAS_STRNLEN 0
+#endif
#endif // SANITIZER_TEST_UTILS_H
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index ddc8dba5d3e0..58c627a704ff 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -11,6 +11,9 @@
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_thread_registry.h"
+
+#include "sanitizer_pthread_wrappers.h"
+
#include "gtest/gtest.h"
#include <vector>
@@ -48,7 +51,7 @@ static uptr get_uid(u32 tid) {
static bool HasName(ThreadContextBase *tctx, void *arg) {
char *name = (char*)arg;
- return (tctx->name && 0 == internal_strcmp(tctx->name, name));
+ return (0 == internal_strcmp(tctx->name, name));
}
static bool HasUid(ThreadContextBase *tctx, void *arg) {
@@ -104,13 +107,13 @@ static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
registry->FindThread(HasUid, (void*)0x1234));
// Detach and finish and join remaining threads.
for (u32 i = 6; i <= 10; i++) {
- registry->DetachThread(i);
+ registry->DetachThread(i, 0);
registry->FinishThread(i);
}
for (u32 i = 0; i < new_tids.size(); i++) {
u32 tid = new_tids[i];
registry->StartThread(tid, 0, 0);
- registry->DetachThread(tid);
+ registry->DetachThread(tid, 0);
registry->FinishThread(tid);
}
CheckThreadQuantity(registry, exp_total, 1, 1);
@@ -203,10 +206,10 @@ static void ThreadedTestRegistry(ThreadRegistry *registry) {
for (int i = 0; i < kNumShards; i++) {
args[i].registry = registry;
args[i].shard = i + 1;
- pthread_create(&threads[i], 0, RunThread, &args[i]);
+ PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
}
for (int i = 0; i < kNumShards; i++) {
- pthread_join(threads[i], 0);
+ PTHREAD_JOIN(threads[i], 0);
}
// Check that each thread created/started/joined correct amount
// of "threads" in thread_registry.