Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,217 @@
include(CompilerRTCompile)
clang_compiler_add_cxx_check()
# FIXME: use SANITIZER_COMMON_SUPPORTED_ARCH here
filter_available_targets(SANITIZER_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el)
if(APPLE)
darwin_filter_host_archs(SANITIZER_UNITTEST_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH)
endif()
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
sanitizer_list_test.cc
sanitizer_mutex_test.cc
sanitizer_nolibc_test.cc
sanitizer_posix_test.cc
sanitizer_printf_test.cc
sanitizer_procmaps_test.cc
sanitizer_quarantine_test.cc
sanitizer_stackdepot_test.cc
sanitizer_stacktrace_printer_test.cc
sanitizer_stacktrace_test.cc
sanitizer_stoptheworld_test.cc
sanitizer_suppressions_test.cc
sanitizer_symbolizer_test.cc
sanitizer_test_main.cc
sanitizer_thread_registry_test.cc
sanitizer_vector_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_UNITTEST_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
-fno-rtti
-O2
-Werror=sign-compare
-Wno-non-virtual-dtor)
if(MSVC)
# Disable exceptions on Windows until they work reliably.
list(APPEND SANITIZER_TEST_CFLAGS_COMMON -fno-exceptions -DGTEST_HAS_SEH=0)
endif()
# -gline-tables-only must be enough for these tests, so use it if possible.
if(COMPILER_RT_TEST_COMPILER_ID MATCHES "Clang")
list(APPEND SANITIZER_TEST_CFLAGS_COMMON -gline-tables-only)
else()
list(APPEND SANITIZER_TEST_CFLAGS_COMMON -g)
endif()
if(MSVC)
list(APPEND SANITIZER_TEST_CFLAGS_COMMON -gcodeview)
endif()
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON -g)
if(NOT MSVC)
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON --driver-mode=g++)
endif()
if(ANDROID)
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON -pie)
endif()
if(APPLE)
list(APPEND SANITIZER_TEST_CFLAGS_COMMON ${DARWIN_osx_CFLAGS})
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON ${DARWIN_osx_LINK_FLAGS})
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON ${WEAK_SYMBOL_LINK_FLAGS})
endif()
# MSVC linker is allocating 1M for the stack by default, which is not
# enough for the unittests. Some unittests require more than 2M.
# The default stack size for clang is 8M.
if(MSVC)
list(APPEND SANITIZER_TEST_LINK_FLAGS_COMMON -Wl,/STACK:0xC00000)
endif()
set(SANITIZER_TEST_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log SANITIZER_TEST_LINK_LIBS)
# NDK r10 requires -latomic almost always.
append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON)
append_list_if(COMPILER_RT_HAS_LIBRT -lrt 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(../..)
# Adds static library which contains sanitizer_common object file
# (universal binary on Mac and arch-specific object files on Linux).
macro(add_sanitizer_common_lib library)
add_library(${library} STATIC ${ARGN})
set_target_properties(${library} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
FOLDER "Compiler-RT Runtime tests")
endmacro()
function(get_sanitizer_common_lib_for_arch arch lib)
if(APPLE)
set(tgt_name "RTSanitizerCommon.test.osx")
else()
set(tgt_name "RTSanitizerCommon.test.${arch}")
endif()
set(${lib} "${tgt_name}" PARENT_SCOPE)
endfunction()
# Sanitizer_common unit tests testsuite.
add_custom_target(SanitizerUnitTests)
set_target_properties(SanitizerUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
# Adds sanitizer tests for architecture.
macro(add_sanitizer_tests_for_arch arch)
set(extra_flags)
if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
list(APPEND extra_flags "-D_LARGEFILE_SOURCE")
list(APPEND extra_flags "-D_FILE_OFFSET_BITS=64")
endif()
get_sanitizer_common_lib_for_arch(${arch} SANITIZER_COMMON_LIB)
set(SANITIZER_TEST_OBJECTS)
generate_compiler_rt_tests(SANITIZER_TEST_OBJECTS SanitizerUnitTests
"Sanitizer-${arch}-Test" ${arch}
RUNTIME "${SANITIZER_COMMON_LIB}"
SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE}
COMPILE_DEPS ${SANITIZER_TEST_HEADERS}
DEPS gtest
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${extra_flags}
LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON} ${extra_flags})
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND "${arch}" STREQUAL "x86_64")
# Test that the libc-independent part of sanitizer_common is indeed
# independent of libc, by linking this binary without libc (here) and
# executing it (unit test in sanitizer_nolibc_test.cc).
clang_compile(sanitizer_nolibc_test_main.${arch}.o
sanitizer_nolibc_test_main.cc
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${TARGET_FLAGS}
DEPS ${SANITIZER_TEST_COMPILE_DEPS})
add_compiler_rt_test(SanitizerUnitTests "Sanitizer-${arch}-Test-Nolibc" ${arch}
OBJECTS sanitizer_nolibc_test_main.${arch}.o
-Wl,-whole-archive
libRTSanitizerCommon.test.nolibc.${arch}.a
-Wl,-no-whole-archive
DEPS sanitizer_nolibc_test_main.${arch}.o
RTSanitizerCommon.test.nolibc.${arch}
LINK_FLAGS -nostdlib ${TARGET_FLAGS})
endif()
endmacro()
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)
add_sanitizer_common_lib("RTSanitizerCommon.test.osx"
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>)
else()
if(CAN_TARGET_x86_64)
add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64"
$<TARGET_OBJECTS:RTSanitizerCommon.x86_64>
$<TARGET_OBJECTS:RTSanitizerCommonNoLibc.x86_64>)
endif()
foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH})
add_sanitizer_common_lib("RTSanitizerCommon.test.${arch}"
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
endforeach()
endif()
foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH})
add_sanitizer_tests_for_arch(${arch})
endforeach()
endif()
if(ANDROID)
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()

View File

@@ -0,0 +1,37 @@
#include <thread>
#include <iostream>
const size_t kAllocSize = 16;
const size_t kInitialNumAllocs = 1 << 10;
const size_t kPeriodicNumAllocs = 1 << 10;
const size_t kNumIterations = 1 << 7;
const size_t kNumThreads = 16;
void Thread() {
// int sp;
// std::cerr << "Thread starting, sp = " << &sp << std::endl;
char *InitialAllocations[kInitialNumAllocs];
char *PeriodicaAllocations[kPeriodicNumAllocs];
for (auto &p : InitialAllocations) p = new char[kAllocSize];
for (size_t i = 0; i < kNumIterations; i++) {
for (size_t j = 0; j < kPeriodicNumAllocs; j++) {
for (auto &p : PeriodicaAllocations) {
p = new char[kAllocSize];
*p = 0;
}
for (auto p : PeriodicaAllocations) delete [] p;
}
}
for (auto p : InitialAllocations) delete [] p;
}
int main() {
// Thread();
// return 0;
std::thread *Threads[kNumThreads];
for (auto &T : Threads) T = new std::thread(&Thread);
for (auto T : Threads) {
T->join();
delete T;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
//===-- sanitizer_allocator_testlib.cc ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Malloc replacement library based on CombinedAllocator.
// The primary purpose of this file is an end-to-end integration test
// for CombinedAllocator.
//===----------------------------------------------------------------------===//
/* Usage:
clang++ -std=c++11 -fno-exceptions -g -fPIC -I. -I../include -Isanitizer \
sanitizer_common/tests/sanitizer_allocator_testlib.cc \
$(\ls sanitizer_common/sanitizer_*.cc | grep -v sanitizer_common_nolibc.cc) \
sanitizer_common/sanitizer_linux_x86_64.S \
-shared -lpthread -o testmalloc.so
LD_PRELOAD=`pwd`/testmalloc.so /your/app
*/
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_common.h"
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#ifndef SANITIZER_MALLOC_HOOK
# define SANITIZER_MALLOC_HOOK(p, s)
#endif
#ifndef SANITIZER_FREE_HOOK
# define SANITIZER_FREE_HOOK(p)
#endif
static const uptr kAllocatorSpace = 0x600000000000ULL;
static const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
struct __AP64 {
static const uptr kSpaceBeg = ~(uptr)0;
static const uptr kSpaceSize = kAllocatorSize;
static const uptr kMetadataSize = 0;
typedef CompactSizeClassMap SizeClassMap;
typedef NoOpMapUnmapCallback MapUnmapCallback;
static const uptr kFlags =
SizeClassAllocator64FlagMasks::kRandomShuffleChunks;
};
namespace {
typedef SizeClassAllocator64<__AP64> PrimaryAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
SecondaryAllocator> Allocator;
static Allocator allocator;
static bool global_inited;
static THREADLOCAL AllocatorCache cache;
static THREADLOCAL bool thread_inited;
static pthread_key_t pkey;
static void thread_dtor(void *v) {
if ((uptr)v != 3) {
pthread_setspecific(pkey, (void*)((uptr)v + 1));
return;
}
allocator.SwallowCache(&cache);
}
static size_t GetRss() {
if (FILE *f = fopen("/proc/self/statm", "r")) {
size_t size = 0, rss = 0;
fscanf(f, "%zd %zd", &size, &rss);
fclose(f);
return rss << 12; // rss is in pages.
}
return 0;
}
struct AtExit {
~AtExit() {
allocator.PrintStats();
Printf("RSS: %zdM\n", GetRss() >> 20);
}
};
static AtExit at_exit;
static void NOINLINE thread_init() {
if (!global_inited) {
global_inited = true;
allocator.Init(false /*may_return_null*/);
pthread_key_create(&pkey, thread_dtor);
}
thread_inited = true;
pthread_setspecific(pkey, (void*)1);
cache.Init(nullptr);
}
} // namespace
extern "C" {
void *malloc(size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
void *p = allocator.Allocate(&cache, size, 8);
SANITIZER_MALLOC_HOOK(p, size);
return p;
}
void free(void *p) {
if (UNLIKELY(!thread_inited))
thread_init();
SANITIZER_FREE_HOOK(p);
allocator.Deallocate(&cache, p);
}
void *calloc(size_t nmemb, size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
size *= nmemb;
void *p = allocator.Allocate(&cache, size, 8, false);
memset(p, 0, size);
SANITIZER_MALLOC_HOOK(p, size);
return p;
}
void *realloc(void *p, size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
if (p) {
SANITIZER_FREE_HOOK(p);
}
p = allocator.Reallocate(&cache, p, size, 8);
if (p) {
SANITIZER_MALLOC_HOOK(p, size);
}
return p;
}
#if SANITIZER_INTERCEPT_MEMALIGN
void *memalign(size_t alignment, size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
void *p = allocator.Allocate(&cache, size, alignment);
SANITIZER_MALLOC_HOOK(p, size);
return p;
}
#endif // SANITIZER_INTERCEPT_MEMALIGN
int posix_memalign(void **memptr, size_t alignment, size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
*memptr = allocator.Allocate(&cache, size, alignment);
SANITIZER_MALLOC_HOOK(*memptr, size);
return 0;
}
void *valloc(size_t size) {
if (UNLIKELY(!thread_inited))
thread_init();
if (size == 0)
size = GetPageSizeCached();
void *p = allocator.Allocate(&cache, size, GetPageSizeCached());
SANITIZER_MALLOC_HOOK(p, size);
return p;
}
#if SANITIZER_INTERCEPT_CFREE
void cfree(void *p) ALIAS("free");
#endif // SANITIZER_INTERCEPT_CFREE
#if SANITIZER_INTERCEPT_PVALLOC
void *pvalloc(size_t size) ALIAS("valloc");
#endif // SANITIZER_INTERCEPT_PVALLOC
#if SANITIZER_INTERCEPT_MEMALIGN
void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign");
#endif // SANITIZER_INTERCEPT_MEMALIGN
void malloc_usable_size() {
}
#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
void mallinfo() {
}
void mallopt() {
}
#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
} // extern "C"
namespace std {
struct nothrow_t;
}
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) 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");

View File

@@ -0,0 +1,128 @@
//===-- sanitizer_atomic_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.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_atomic.h"
#include "gtest/gtest.h"
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
template<typename T>
void CheckAtomicCompareExchange() {
typedef typename T::Type Type;
{
Type old_val = 42;
Type new_val = 24;
Type var = old_val;
EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_EQ(new_val, old_val);
}
{
Type old_val = 42;
Type new_val = 24;
Type var = old_val;
EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_EQ(new_val, old_val);
}
}
TEST(SanitizerCommon, AtomicCompareExchangeTest) {
CheckAtomicCompareExchange<atomic_uint8_t>();
CheckAtomicCompareExchange<atomic_uint16_t>();
CheckAtomicCompareExchange<atomic_uint32_t>();
CheckAtomicCompareExchange<atomic_uint64_t>();
CheckAtomicCompareExchange<atomic_uintptr_t>();
}
#endif //!SANITIZER_ANDROID
} // namespace __sanitizer

View File

@@ -0,0 +1,178 @@
//===-- 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 <random>
#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, "%lu ", idx);
}
fprintf(stderr, "\n");
}
void Print(const set<uptr> &s) {
for (set<uptr>::iterator it = s.begin(); it != s.end(); ++it) {
fprintf(stderr, "%lu ", *it);
}
fprintf(stderr, "\n");
}
template <class BV>
void TestBitVector(uptr expected_size) {
std::mt19937 r;
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;
std::shuffle(bits.begin(), bits.end(), r);
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);
}

View File

@@ -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>();
}

View File

@@ -0,0 +1,388 @@
//===-- sanitizer_common_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.
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_file.h"
#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 {
static bool IsSorted(const uptr *array, uptr n) {
for (uptr i = 1; i < n; i++) {
if (array[i] < array[i - 1]) return false;
}
return true;
}
TEST(SanitizerCommon, SortTest) {
uptr array[100];
uptr n = 100;
// Already sorted.
for (uptr i = 0; i < n; i++) {
array[i] = i;
}
SortArray(array, n);
EXPECT_TRUE(IsSorted(array, n));
// Reverse order.
for (uptr i = 0; i < n; i++) {
array[i] = n - 1 - i;
}
SortArray(array, n);
EXPECT_TRUE(IsSorted(array, n));
// Mixed order.
for (uptr i = 0; i < n; i++) {
array[i] = (i % 2 == 0) ? i : n - 1 - i;
}
SortArray(array, n);
EXPECT_TRUE(IsSorted(array, n));
// All equal.
for (uptr i = 0; i < n; i++) {
array[i] = 42;
}
SortArray(array, n);
EXPECT_TRUE(IsSorted(array, n));
// All but one sorted.
for (uptr i = 0; i < n - 1; i++) {
array[i] = i;
}
array[n - 1] = 42;
SortArray(array, n);
EXPECT_TRUE(IsSorted(array, n));
// Minimal case - sort three elements.
array[0] = 1;
array[1] = 0;
SortArray(array, 2);
EXPECT_TRUE(IsSorted(array, 2));
}
TEST(SanitizerCommon, MmapAlignedOrDieOnFatalError) {
uptr PageSize = GetPageSizeCached();
for (uptr size = 1; size <= 32; size *= 2) {
for (uptr alignment = 1; alignment <= 32; alignment *= 2) {
for (int iter = 0; iter < 100; iter++) {
uptr res = (uptr)MmapAlignedOrDieOnFatalError(
size * PageSize, alignment * PageSize, "MmapAlignedOrDieTest");
EXPECT_EQ(0U, res % (alignment * PageSize));
internal_memset((void*)res, 1, size * PageSize);
UnmapOrDie((void*)res, size * PageSize);
}
}
}
}
#if SANITIZER_LINUX
TEST(SanitizerCommon, SanitizerSetThreadName) {
const char *names[] = {
"0123456789012",
"01234567890123",
"012345678901234", // Larger names will be truncated on linux.
};
for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
EXPECT_TRUE(SanitizerSetThreadName(names[i]));
char buff[100];
EXPECT_TRUE(SanitizerGetThreadName(buff, sizeof(buff) - 1));
EXPECT_EQ(0, internal_strcmp(buff, names[i]));
}
}
#endif
TEST(SanitizerCommon, InternalMmapVector) {
InternalMmapVector<uptr> vector(1);
for (uptr i = 0; i < 100; i++) {
EXPECT_EQ(i, vector.size());
vector.push_back(i);
}
for (uptr i = 0; i < 100; i++) {
EXPECT_EQ(i, vector[i]);
}
for (int i = 99; i >= 0; i--) {
EXPECT_EQ((uptr)i, vector.back());
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) {
uptr stk_addr = 0;
uptr stk_size = 0;
uptr tls_addr = 0;
uptr tls_size = 0;
GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
int stack_var;
EXPECT_NE(stk_addr, (uptr)0);
EXPECT_NE(stk_size, (uptr)0);
EXPECT_GT((uptr)&stack_var, stk_addr);
EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
#if SANITIZER_LINUX && defined(__x86_64__)
static __thread int thread_var;
EXPECT_NE(tls_addr, (uptr)0);
EXPECT_NE(tls_size, (uptr)0);
EXPECT_GT((uptr)&thread_var, tls_addr);
EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
// Ensure that tls and stack do not intersect.
uptr tls_end = tls_addr + tls_size;
EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size);
EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr));
#endif
}
static void *WorkerThread(void *arg) {
TestThreadInfo(false);
return 0;
}
TEST(SanitizerCommon, ThreadStackTlsMain) {
InitTlsSize();
TestThreadInfo(true);
}
TEST(SanitizerCommon, ThreadStackTlsWorker) {
InitTlsSize();
pthread_t t;
PTHREAD_CREATE(&t, 0, WorkerThread, 0);
PTHREAD_JOIN(t, 0);
}
bool UptrLess(uptr a, uptr b) {
return a < b;
}
TEST(SanitizerCommon, InternalLowerBound) {
static const uptr kSize = 5;
int arr[kSize];
arr[0] = 1;
arr[1] = 3;
arr[2] = 5;
arr[3] = 7;
arr[4] = 11;
EXPECT_EQ(0u, InternalLowerBound(arr, 0, kSize, 0, UptrLess));
EXPECT_EQ(0u, InternalLowerBound(arr, 0, kSize, 1, UptrLess));
EXPECT_EQ(1u, InternalLowerBound(arr, 0, kSize, 2, UptrLess));
EXPECT_EQ(1u, InternalLowerBound(arr, 0, kSize, 3, UptrLess));
EXPECT_EQ(2u, InternalLowerBound(arr, 0, kSize, 4, UptrLess));
EXPECT_EQ(2u, InternalLowerBound(arr, 0, kSize, 5, UptrLess));
EXPECT_EQ(3u, InternalLowerBound(arr, 0, kSize, 6, UptrLess));
EXPECT_EQ(3u, InternalLowerBound(arr, 0, kSize, 7, UptrLess));
EXPECT_EQ(4u, InternalLowerBound(arr, 0, kSize, 8, UptrLess));
EXPECT_EQ(4u, InternalLowerBound(arr, 0, kSize, 9, UptrLess));
EXPECT_EQ(4u, InternalLowerBound(arr, 0, kSize, 10, UptrLess));
EXPECT_EQ(4u, InternalLowerBound(arr, 0, kSize, 11, UptrLess));
EXPECT_EQ(5u, InternalLowerBound(arr, 0, kSize, 12, UptrLess));
}
TEST(SanitizerCommon, InternalLowerBoundVsStdLowerBound) {
std::vector<int> data;
auto create_item = [] (size_t i, size_t j) {
auto v = i * 10000 + j;
return ((v << 6) + (v >> 6) + 0x9e3779b9) % 100;
};
for (size_t i = 0; i < 1000; ++i) {
data.resize(i);
for (size_t j = 0; j < i; ++j) {
data[j] = create_item(i, j);
}
std::sort(data.begin(), data.end());
for (size_t j = 0; j < i; ++j) {
int val = create_item(i, j);
for (auto to_find : {val - 1, val, val + 1}) {
uptr expected =
std::lower_bound(data.begin(), data.end(), to_find) - data.begin();
EXPECT_EQ(expected, InternalLowerBound(data.data(), 0, data.size(),
to_find, std::less<int>()));
}
}
}
}
#if SANITIZER_LINUX && !SANITIZER_ANDROID
TEST(SanitizerCommon, FindPathToBinary) {
char *true_path = FindPathToBinary("true");
EXPECT_NE((char*)0, internal_strstr(true_path, "/bin/true"));
InternalFree(true_path);
EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj"));
}
#elif SANITIZER_WINDOWS
TEST(SanitizerCommon, FindPathToBinary) {
// ntdll.dll should be on PATH in all supported test environments on all
// supported Windows versions.
char *ntdll_path = FindPathToBinary("ntdll.dll");
EXPECT_NE((char*)0, internal_strstr(ntdll_path, "ntdll.dll"));
InternalFree(ntdll_path);
EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj"));
}
#endif
TEST(SanitizerCommon, StripPathPrefix) {
EXPECT_EQ(0, StripPathPrefix(0, "prefix"));
EXPECT_STREQ("foo", StripPathPrefix("foo", 0));
EXPECT_STREQ("dir/file.cc",
StripPathPrefix("/usr/lib/dir/file.cc", "/usr/lib/"));
EXPECT_STREQ("/file.cc", StripPathPrefix("/usr/myroot/file.cc", "/myroot"));
EXPECT_STREQ("file.h", StripPathPrefix("/usr/lib/./file.h", "/usr/lib/"));
}
TEST(SanitizerCommon, RemoveANSIEscapeSequencesFromString) {
RemoveANSIEscapeSequencesFromString(nullptr);
const char *buffs[22] = {
"Default", "Default",
"\033[95mLight magenta", "Light magenta",
"\033[30mBlack\033[32mGreen\033[90mGray", "BlackGreenGray",
"\033[106mLight cyan \033[107mWhite ", "Light cyan White ",
"\033[31mHello\033[0m World", "Hello World",
"\033[38;5;82mHello \033[38;5;198mWorld", "Hello World",
"123[653456789012", "123[653456789012",
"Normal \033[5mBlink \033[25mNormal", "Normal Blink Normal",
"\033[106m\033[107m", "",
"", "",
" ", " ",
};
for (size_t i = 0; i < ARRAY_SIZE(buffs); i+=2) {
char *buffer_copy = internal_strdup(buffs[i]);
RemoveANSIEscapeSequencesFromString(buffer_copy);
EXPECT_STREQ(buffer_copy, buffs[i+1]);
InternalFree(buffer_copy);
}
}
TEST(SanitizerCommon, InternalScopedString) {
InternalScopedString str(10);
EXPECT_EQ(0U, str.length());
EXPECT_STREQ("", str.data());
str.append("foo");
EXPECT_EQ(3U, str.length());
EXPECT_STREQ("foo", str.data());
int x = 1234;
str.append("%d", x);
EXPECT_EQ(7U, str.length());
EXPECT_STREQ("foo1234", str.data());
str.append("%d", x);
EXPECT_EQ(9U, str.length());
EXPECT_STREQ("foo123412", str.data());
str.clear();
EXPECT_EQ(0U, str.length());
EXPECT_STREQ("", str.data());
str.append("0123456789");
EXPECT_EQ(9U, str.length());
EXPECT_STREQ("012345678", str.data());
}
#if SANITIZER_LINUX
TEST(SanitizerCommon, GetRandom) {
u8 buffer_1[32], buffer_2[32];
for (bool blocking : { false, true }) {
EXPECT_FALSE(GetRandom(nullptr, 32, blocking));
EXPECT_FALSE(GetRandom(buffer_1, 0, blocking));
EXPECT_FALSE(GetRandom(buffer_1, 512, blocking));
EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2));
for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) {
for (uptr i = 0; i < 100; i++) {
EXPECT_TRUE(GetRandom(buffer_1, size, blocking));
EXPECT_TRUE(GetRandom(buffer_2, size, blocking));
EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0);
}
}
}
}
#endif
TEST(SanitizerCommon, ReservedAddressRangeInit) {
uptr init_size = 0xffff;
ReservedAddressRange address_range;
uptr res = address_range.Init(init_size);
CHECK_NE(res, (void*)-1);
UnmapOrDie((void*)res, init_size);
// Should be able to map into the same space now.
ReservedAddressRange address_range2;
uptr res2 = address_range2.Init(init_size, nullptr, res);
CHECK_EQ(res, res2);
// TODO(flowerhack): Once this is switched to the "real" implementation
// (rather than passing through to MmapNoAccess*), enforce and test "no
// double initializations allowed"
}
TEST(SanitizerCommon, ReservedAddressRangeMap) {
constexpr uptr init_size = 0xffff;
ReservedAddressRange address_range;
uptr res = address_range.Init(init_size);
CHECK_NE(res, (void*) -1);
// Valid mappings should succeed.
CHECK_EQ(res, address_range.Map(res, init_size));
// Valid mappings should be readable.
unsigned char buffer[init_size];
memcpy(buffer, reinterpret_cast<void *>(res), init_size);
// TODO(flowerhack): Once this is switched to the "real" implementation, make
// sure you can only mmap into offsets in the Init range.
}
TEST(SanitizerCommon, ReservedAddressRangeUnmap) {
uptr PageSize = GetPageSizeCached();
uptr init_size = PageSize * 8;
ReservedAddressRange address_range;
uptr base_addr = address_range.Init(init_size);
CHECK_NE(base_addr, (void*)-1);
CHECK_EQ(base_addr, address_range.Map(base_addr, init_size));
// Unmapping the entire range should succeed.
address_range.Unmap(base_addr, init_size);
// Map a new range.
base_addr = address_range.Init(init_size);
CHECK_EQ(base_addr, address_range.Map(base_addr, init_size));
// Windows doesn't allow partial unmappings.
#if !SANITIZER_WINDOWS
// Unmapping at the beginning should succeed.
address_range.Unmap(base_addr, PageSize);
// Unmapping at the end should succeed.
uptr new_start = reinterpret_cast<uptr>(address_range.base()) +
address_range.size() - PageSize;
address_range.Unmap(new_start, PageSize);
#endif
// Unmapping in the middle of the ReservedAddressRange should fail.
EXPECT_DEATH(address_range.Unmap(base_addr + (PageSize * 2), PageSize), ".*");
}
} // namespace __sanitizer

View File

@@ -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 !SANITIZER_DEBUG
// 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>();
}

View File

@@ -0,0 +1,180 @@
//===-- sanitizer_flags_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.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "gtest/gtest.h"
#include <string.h>
namespace __sanitizer {
static const char kFlagName[] = "flag_name";
static const char kFlagDesc[] = "flag description";
template <typename T>
static void TestFlag(T start_value, const char *env, T final_value) {
T flag = start_value;
FlagParser parser;
RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
parser.ParseString(env);
EXPECT_EQ(final_value, flag);
}
template <>
void TestFlag(const char *start_value, const char *env,
const char *final_value) {
const char *flag = start_value;
FlagParser parser;
RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
parser.ParseString(env);
EXPECT_EQ(0, internal_strcmp(final_value, flag));
// Reporting unrecognized flags is needed to reset them.
ReportUnrecognizedFlags();
}
TEST(SanitizerCommon, BooleanFlags) {
TestFlag(false, "flag_name=1", true);
TestFlag(false, "flag_name=yes", true);
TestFlag(false, "flag_name=true", true);
TestFlag(true, "flag_name=0", false);
TestFlag(true, "flag_name=no", false);
TestFlag(true, "flag_name=false", false);
EXPECT_DEATH(TestFlag(false, "flag_name", true), "expected '='");
EXPECT_DEATH(TestFlag(false, "flag_name=", true),
"Invalid value for bool option: ''");
EXPECT_DEATH(TestFlag(false, "flag_name=2", true),
"Invalid value for bool option: '2'");
EXPECT_DEATH(TestFlag(false, "flag_name=-1", true),
"Invalid value for bool option: '-1'");
EXPECT_DEATH(TestFlag(false, "flag_name=on", true),
"Invalid value for bool option: 'on'");
}
TEST(SanitizerCommon, HandleSignalMode) {
TestFlag(kHandleSignalNo, "flag_name=1", kHandleSignalYes);
TestFlag(kHandleSignalNo, "flag_name=yes", kHandleSignalYes);
TestFlag(kHandleSignalNo, "flag_name=true", kHandleSignalYes);
TestFlag(kHandleSignalYes, "flag_name=0", kHandleSignalNo);
TestFlag(kHandleSignalYes, "flag_name=no", kHandleSignalNo);
TestFlag(kHandleSignalYes, "flag_name=false", kHandleSignalNo);
TestFlag(kHandleSignalNo, "flag_name=2", kHandleSignalExclusive);
TestFlag(kHandleSignalYes, "flag_name=exclusive", kHandleSignalExclusive);
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name", kHandleSignalNo),
"expected '='");
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=", kHandleSignalNo),
"Invalid value for signal handler option: ''");
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=3", kHandleSignalNo),
"Invalid value for signal handler option: '3'");
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=-1", kHandleSignalNo),
"Invalid value for signal handler option: '-1'");
EXPECT_DEATH(TestFlag(kHandleSignalNo, "flag_name=on", kHandleSignalNo),
"Invalid value for signal handler option: 'on'");
}
TEST(SanitizerCommon, IntFlags) {
TestFlag(-11, 0, -11);
TestFlag(-11, "flag_name=0", 0);
TestFlag(-11, "flag_name=42", 42);
TestFlag(-11, "flag_name=-42", -42);
// Unrecognized flags are ignored.
TestFlag(-11, "--flag_name=42", -11);
TestFlag(-11, "zzzzzzz=42", -11);
EXPECT_DEATH(TestFlag(-11, "flag_name", 0), "expected '='");
EXPECT_DEATH(TestFlag(-11, "flag_name=42U", 0),
"Invalid value for int option");
}
TEST(SanitizerCommon, StrFlags) {
TestFlag("zzz", 0, "zzz");
TestFlag("zzz", "flag_name=", "");
TestFlag("zzz", "flag_name=abc", "abc");
TestFlag("", "flag_name=abc", "abc");
TestFlag("", "flag_name='abc zxc'", "abc zxc");
// TestStrFlag("", "flag_name=\"abc qwe\" asd", "abc qwe");
}
static void TestTwoFlags(const char *env, bool expected_flag1,
const char *expected_flag2,
const char *name1 = "flag1",
const char *name2 = "flag2") {
bool flag1 = !expected_flag1;
const char *flag2 = "";
FlagParser parser;
RegisterFlag(&parser, name1, kFlagDesc, &flag1);
RegisterFlag(&parser, name2, kFlagDesc, &flag2);
parser.ParseString(env);
EXPECT_EQ(expected_flag1, flag1);
EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
// Reporting unrecognized flags is needed to reset them.
ReportUnrecognizedFlags();
}
TEST(SanitizerCommon, MultipleFlags) {
TestTwoFlags("flag1=1 flag2='zzz'", true, "zzz");
TestTwoFlags("flag2='qxx' flag1=0", false, "qxx");
TestTwoFlags("flag1=false:flag2='zzz'", false, "zzz");
TestTwoFlags("flag2=qxx:flag1=yes", true, "qxx");
TestTwoFlags("flag2=qxx\nflag1=yes", true, "qxx");
TestTwoFlags("flag2=qxx\r\nflag1=yes", true, "qxx");
TestTwoFlags("flag2=qxx\tflag1=yes", true, "qxx");
}
TEST(SanitizerCommon, CommonSuffixFlags) {
TestTwoFlags("flag=1 other_flag='zzz'", true, "zzz", "flag", "other_flag");
TestTwoFlags("other_flag='zzz' flag=1", true, "zzz", "flag", "other_flag");
TestTwoFlags("other_flag=' flag=0 ' flag=1", true, " flag=0 ", "flag",
"other_flag");
TestTwoFlags("flag=1 other_flag=' flag=0 '", true, " flag=0 ", "flag",
"other_flag");
}
TEST(SanitizerCommon, CommonFlags) {
CommonFlags cf;
FlagParser parser;
RegisterCommonFlags(&parser, &cf);
cf.SetDefaults();
EXPECT_TRUE(cf.symbolize);
EXPECT_STREQ(".", cf.coverage_dir);
cf.symbolize = false;
cf.coverage = true;
cf.heap_profile = true;
cf.log_path = "path/one";
parser.ParseString("symbolize=1:heap_profile=false log_path='path/two'");
EXPECT_TRUE(cf.symbolize);
EXPECT_TRUE(cf.coverage);
EXPECT_FALSE(cf.heap_profile);
EXPECT_STREQ("path/two", cf.log_path);
}
} // namespace __sanitizer

View File

@@ -0,0 +1,263 @@
//===-- sanitizer_format_interceptor_test.cc ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// 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) \
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 << "'";
}
static const char test_buf[] = "Test string.";
static const size_t test_buf_size = sizeof(test_buf);
static const unsigned SCANF_ARGS_MAX = 16;
static void testScanf3(void *ctx, int result, bool allowGnuMalloc,
const char *format, ...) {
va_list ap;
va_start(ap, format);
scanf_common(ctx, result, allowGnuMalloc, format, ap);
va_end(ap);
}
static void testScanf2(const char *format, int scanf_result,
bool allowGnuMalloc, unsigned n,
va_list expected_sizes) {
std::vector<unsigned> scanf_sizes;
// 16 args should be enough.
testScanf3((void *)&scanf_sizes, scanf_result, allowGnuMalloc, 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, ...) {
va_list ap;
va_start(ap, n);
testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ true, n, ap);
va_end(ap);
}
static void testScanfPartial(const char *format, int scanf_result, unsigned n,
...) {
va_list ap;
va_start(ap, n);
testScanf2(format, scanf_result, /* allowGnuMalloc */ true, n, ap);
va_end(ap);
}
static void testScanfNoGnuMalloc(const char *format, unsigned n, ...) {
va_list ap;
va_start(ap, n);
testScanf2(format, SCANF_ARGS_MAX, /* allowGnuMalloc */ false, n, ap);
va_end(ap);
}
TEST(SanitizerCommonInterceptors, Scanf) {
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);
testScanf("a%%b", 0);
testScanf("a%%%%b", 0);
testScanf("a%%b%%", 0);
testScanf("a%%%%%%b", 0);
testScanf("a%%%%%b", 0);
testScanf("a%%%%%f", 1, F);
testScanf("a%%%lxb", 1, L);
testScanf("a%lf%%%lxb", 2, D, L);
testScanf("%nf", 1, I);
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, test_buf_size, I);
testScanf("%[abc]", 1, test_buf_size);
testScanf("%4[bcdef]", 1, 5);
testScanf("%[]]", 1, test_buf_size);
testScanf("%8[^]%d0-9-]%c", 2, 9, C);
testScanf("%*[^:]%n:%d:%1[ ]%n", 4, I, I, 2, I);
testScanf("%*d%u", 1, I);
testScanf("%c%d", 2, C, I);
testScanf("%A%lf", 2, F, D);
testScanf("%ms %Lf", 2, P, LD);
testScanf("s%Las", 1, LD);
testScanf("%ar", 1, F);
// In the cases with std::min below the format spec can be interpreted as
// either floating-something, or (GNU extension) callee-allocated string.
// Our conservative implementation reports one of the two possibilities with
// the least store range.
testScanf("%a[", 0);
testScanf("%a[]", 0);
testScanf("%a[]]", 1, std::min(F, P));
testScanf("%a[abc]", 1, std::min(F, P));
testScanf("%a[^abc]", 1, std::min(F, P));
testScanf("%a[ab%c] %d", 0);
testScanf("%a[^ab%c] %d", 0);
testScanf("%as", 1, std::min(F, P));
testScanf("%aS", 1, std::min(F, P));
testScanf("%a13S", 1, std::min(F, P));
testScanf("%alS", 1, std::min(F, P));
testScanfNoGnuMalloc("s%Las", 1, LD);
testScanfNoGnuMalloc("%ar", 1, F);
testScanfNoGnuMalloc("%a[", 1, F);
testScanfNoGnuMalloc("%a[]", 1, F);
testScanfNoGnuMalloc("%a[]]", 1, F);
testScanfNoGnuMalloc("%a[abc]", 1, F);
testScanfNoGnuMalloc("%a[^abc]", 1, F);
testScanfNoGnuMalloc("%a[ab%c] %d", 3, F, C, I);
testScanfNoGnuMalloc("%a[^ab%c] %d", 3, F, C, I);
testScanfNoGnuMalloc("%as", 1, F);
testScanfNoGnuMalloc("%aS", 1, F);
testScanfNoGnuMalloc("%a13S", 1, F);
testScanfNoGnuMalloc("%alS", 1, F);
testScanf("%5$d", 0);
testScanf("%md", 0);
testScanf("%m10s", 0);
testScanfPartial("%d%d%d%d //1\n", 1, 1, I);
testScanfPartial("%d%d%d%d //2\n", 2, 2, I, I);
testScanfPartial("%d%d%d%d //3\n", 3, 3, I, I, I);
testScanfPartial("%d%d%d%d //4\n", 4, 4, I, I, I, I);
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, 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);
testPrintf("%m", 0);
testPrintf("%m%s", 1, test_buf_size);
testPrintf("%s%m%s", 2, test_buf_size, test_buf_size);
}

View File

@@ -0,0 +1,105 @@
//===-- sanitizer_ioctl_test.cc -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for ioctl interceptor implementation in sanitizer_common.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX
#include <linux/input.h>
#include <vector>
#include "interception/interception.h"
#include "sanitizer_test_utils.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_common.h"
#include "gtest/gtest.h"
using namespace __sanitizer;
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \
do { \
(void) ctx; \
(void) ptr; \
(void) sz; \
} while (0)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \
do { \
(void) ctx; \
(void) ptr; \
(void) sz; \
} while (0)
#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc"
static struct IoctlInit {
IoctlInit() {
ioctl_init();
// Avoid unused function warnings.
(void)&ioctl_common_pre;
(void)&ioctl_common_post;
(void)&ioctl_decode;
}
} ioctl_static_initializer;
TEST(SanitizerIoctl, Fixup) {
EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO));
EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16)));
EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16)));
EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17)));
EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16)));
EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16)));
EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0)));
EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5)));
EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63)));
EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64)));
EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0)));
EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5)));
EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63)));
EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64)));
const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16));
EXPECT_NE((void *)0, desc);
EXPECT_EQ(EVIOCGKEY(0), desc->req);
}
// Test decoding KVM ioctl numbers.
TEST(SanitizerIoctl, KVM_GET_MP_STATE) {
ioctl_desc desc;
unsigned int desc_value = SANITIZER_MIPS ? 0x4004ae98U : 0x8004ae98U;
bool res = ioctl_decode(desc_value, &desc);
EXPECT_TRUE(res);
EXPECT_EQ(ioctl_desc::WRITE, desc.type);
EXPECT_EQ(4U, desc.size);
}
TEST(SanitizerIoctl, KVM_GET_LAPIC) {
ioctl_desc desc;
unsigned int desc_value = SANITIZER_MIPS ? 0x4400ae8eU : 0x8400ae8eU;
bool res = ioctl_decode(desc_value, &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

View File

@@ -0,0 +1,244 @@
//===-- sanitizer_libc_test.cc --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests for sanitizer_libc.h.
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_platform.h"
#include "gtest/gtest.h"
#if SANITIZER_WINDOWS
#define NOMINMAX
#include <windows.h>
#undef NOMINMAX
#endif
#if SANITIZER_POSIX
# include <sys/stat.h>
# include "sanitizer_common/sanitizer_posix.h"
#endif
using namespace __sanitizer;
// A regression test for internal_memmove() implementation.
TEST(SanitizerCommon, InternalMemmoveRegression) {
char src[] = "Hello World";
char *dest = src + 6;
__sanitizer::internal_memmove(dest, src, 5);
EXPECT_EQ(dest[0], src[0]);
EXPECT_EQ(dest[4], src[4]);
}
TEST(SanitizerCommon, mem_is_zero) {
size_t size = 128;
char *x = new char[size];
memset(x, 0, size);
for (size_t pos = 0; pos < size; pos++) {
x[pos] = 1;
for (size_t beg = 0; beg < size; beg++) {
for (size_t end = beg; end < size; end++) {
// fprintf(stderr, "pos %zd beg %zd end %zd \n", pos, beg, end);
if (beg <= pos && pos < end)
EXPECT_FALSE(__sanitizer::mem_is_zero(x + beg, end - beg));
else
EXPECT_TRUE(__sanitizer::mem_is_zero(x + beg, end - beg));
}
}
x[pos] = 0;
}
delete [] x;
}
struct stat_and_more {
struct stat st;
unsigned char z;
};
static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
#if SANITIZER_WINDOWS
buf[0] = '\0';
char tmp_dir[MAX_PATH];
if (!::GetTempPathA(MAX_PATH, tmp_dir))
return;
// GetTempFileNameA needs a MAX_PATH buffer.
char tmp_path[MAX_PATH];
if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path))
return;
internal_strncpy(buf, tmp_path, bufsize);
#else
const char *tmpdir = "/tmp";
#if SANITIZER_ANDROID
// I don't know a way to query temp directory location on Android without
// going through Java interfaces. The code below is not ideal, but should
// work. May require "adb root", but it is needed for almost any use of ASan
// on Android already.
tmpdir = GetEnv("EXTERNAL_STORAGE");
#endif
u32 uid = GetUid();
internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid);
#endif
}
TEST(SanitizerCommon, FileOps) {
const char *str1 = "qwerty";
uptr len1 = internal_strlen(str1);
const char *str2 = "zxcv";
uptr len2 = internal_strlen(str2);
char tmpfile[128];
temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp.");
fd_t fd = OpenFile(tmpfile, WrOnly);
ASSERT_NE(fd, kInvalidFd);
uptr bytes_written = 0;
EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written));
EXPECT_EQ(len1, bytes_written);
EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written));
EXPECT_EQ(len2, bytes_written);
CloseFile(fd);
EXPECT_TRUE(FileExists(tmpfile));
fd = OpenFile(tmpfile, RdOnly);
ASSERT_NE(fd, kInvalidFd);
#if SANITIZER_POSIX
// The stat wrappers are posix-only.
uptr fsize = internal_filesize(fd);
EXPECT_EQ(len1 + len2, fsize);
struct stat st1, st2, st3;
EXPECT_EQ(0u, internal_stat(tmpfile, &st1));
EXPECT_EQ(0u, internal_lstat(tmpfile, &st2));
EXPECT_EQ(0u, internal_fstat(fd, &st3));
EXPECT_EQ(fsize, (uptr)st3.st_size);
// Verify that internal_fstat does not write beyond the end of the supplied
// buffer.
struct stat_and_more sam;
memset(&sam, 0xAB, sizeof(sam));
EXPECT_EQ(0u, internal_fstat(fd, &sam.st));
EXPECT_EQ(0xAB, sam.z);
EXPECT_NE(0xAB, sam.st.st_size);
EXPECT_NE(0, sam.st.st_size);
#endif
char buf[64] = {};
uptr bytes_read = 0;
EXPECT_TRUE(ReadFromFile(fd, buf, len1, &bytes_read));
EXPECT_EQ(len1, bytes_read);
EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
EXPECT_EQ((char)0, buf[len1 + 1]);
internal_memset(buf, 0, len1);
EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read));
EXPECT_EQ(len2, bytes_read);
EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
CloseFile(fd);
#if SANITIZER_WINDOWS
// No sanitizer needs to delete a file on Windows yet. If we ever do, we can
// add a portable wrapper and test it from here.
::DeleteFileA(&tmpfile[0]);
#else
internal_unlink(tmpfile);
#endif
}
static const size_t kStrlcpyBufSize = 8;
void test_internal_strlcpy(char *dbuf, const char *sbuf) {
uptr retval = 0;
retval = internal_strlcpy(dbuf, sbuf, kStrlcpyBufSize);
EXPECT_EQ(internal_strncmp(dbuf, sbuf, kStrlcpyBufSize - 1), 0);
EXPECT_EQ(internal_strlen(dbuf),
std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1)));
EXPECT_EQ(retval, internal_strlen(sbuf));
// Test with shorter maxlen.
uptr maxlen = 2;
if (internal_strlen(sbuf) > maxlen) {
retval = internal_strlcpy(dbuf, sbuf, maxlen);
EXPECT_EQ(internal_strncmp(dbuf, sbuf, maxlen - 1), 0);
EXPECT_EQ(internal_strlen(dbuf), maxlen - 1);
}
}
TEST(SanitizerCommon, InternalStrFunctions) {
const char *haystack = "haystack";
EXPECT_EQ(haystack + 2, internal_strchr(haystack, 'y'));
EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y'));
EXPECT_EQ(0, internal_strchr(haystack, 'z'));
EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z'));
char dbuf[kStrlcpyBufSize] = {};
const char *samesizestr = "1234567";
const char *shortstr = "123";
const char *longerstr = "123456789";
// Test internal_strlcpy.
internal_strlcpy(dbuf, shortstr, 0);
EXPECT_EQ(dbuf[0], 0);
EXPECT_EQ(dbuf[0], 0);
test_internal_strlcpy(dbuf, samesizestr);
test_internal_strlcpy(dbuf, shortstr);
test_internal_strlcpy(dbuf, longerstr);
// Test internal_strlcat.
char dcatbuf[kStrlcpyBufSize] = {};
uptr retval = 0;
retval = internal_strlcat(dcatbuf, "aaa", 0);
EXPECT_EQ(internal_strlen(dcatbuf), (uptr)0);
EXPECT_EQ(retval, (uptr)3);
retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
EXPECT_EQ(internal_strcmp(dcatbuf, "123"), 0);
EXPECT_EQ(internal_strlen(dcatbuf), (uptr)3);
EXPECT_EQ(retval, (uptr)3);
retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
EXPECT_EQ(internal_strcmp(dcatbuf, "123123"), 0);
EXPECT_EQ(internal_strlen(dcatbuf), (uptr)6);
EXPECT_EQ(retval, (uptr)6);
retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize);
EXPECT_EQ(internal_strcmp(dcatbuf, "1231231"), 0);
EXPECT_EQ(internal_strlen(dcatbuf), (uptr)7);
EXPECT_EQ(retval, (uptr)9);
}
// FIXME: File manipulations are not yet supported on Windows
#if SANITIZER_POSIX && !SANITIZER_MAC
TEST(SanitizerCommon, InternalMmapWithOffset) {
char tmpfile[128];
temp_file_name(tmpfile, sizeof(tmpfile),
"sanitizer_common.internalmmapwithoffset.tmp.");
fd_t fd = OpenFile(tmpfile, RdWr);
ASSERT_NE(fd, kInvalidFd);
uptr page_size = GetPageSizeCached();
uptr res = internal_ftruncate(fd, page_size * 2);
ASSERT_FALSE(internal_iserror(res));
res = internal_lseek(fd, page_size, SEEK_SET);
ASSERT_FALSE(internal_iserror(res));
res = internal_write(fd, "AB", 2);
ASSERT_FALSE(internal_iserror(res));
char *p = (char *)MapWritableFileToMemory(nullptr, page_size, fd, page_size);
ASSERT_NE(nullptr, p);
ASSERT_EQ('A', p[0]);
ASSERT_EQ('B', p[1]);
CloseFile(fd);
UnmapOrDie(p, page_size);
internal_unlink(tmpfile);
}
#endif

View File

@@ -0,0 +1,304 @@
//===-- sanitizer_linux_test.cc -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for sanitizer_linux.h
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_file.h"
#include "gtest/gtest.h"
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
namespace __sanitizer {
struct TidReporterArgument {
TidReporterArgument() {
pthread_mutex_init(&terminate_thread_mutex, NULL);
pthread_mutex_init(&tid_reported_mutex, NULL);
pthread_cond_init(&terminate_thread_cond, NULL);
pthread_cond_init(&tid_reported_cond, NULL);
terminate_thread = false;
}
~TidReporterArgument() {
pthread_mutex_destroy(&terminate_thread_mutex);
pthread_mutex_destroy(&tid_reported_mutex);
pthread_cond_destroy(&terminate_thread_cond);
pthread_cond_destroy(&tid_reported_cond);
}
pid_t reported_tid;
// For signaling to spawned threads that they should terminate.
pthread_cond_t terminate_thread_cond;
pthread_mutex_t terminate_thread_mutex;
bool terminate_thread;
// For signaling to main thread that a child thread has reported its tid.
pthread_cond_t tid_reported_cond;
pthread_mutex_t tid_reported_mutex;
private:
// Disallow evil constructors
TidReporterArgument(const TidReporterArgument &);
void operator=(const TidReporterArgument &);
};
class ThreadListerTest : public ::testing::Test {
protected:
virtual void SetUp() {
pthread_t pthread_id;
pid_t tid;
for (uptr i = 0; i < kThreadCount; i++) {
SpawnTidReporter(&pthread_id, &tid);
pthread_ids_.push_back(pthread_id);
tids_.push_back(tid);
}
}
virtual void TearDown() {
pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
thread_arg.terminate_thread = true;
pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
for (uptr i = 0; i < pthread_ids_.size(); i++)
pthread_join(pthread_ids_[i], NULL);
}
void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid);
static const uptr kThreadCount = 20;
std::vector<pthread_t> pthread_ids_;
std::vector<pid_t> tids_;
TidReporterArgument thread_arg;
};
// Writes its TID once to reported_tid and waits until signaled to terminate.
void *TidReporterThread(void *argument) {
TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
pthread_mutex_lock(&arg->tid_reported_mutex);
arg->reported_tid = GetTid();
pthread_cond_broadcast(&arg->tid_reported_cond);
pthread_mutex_unlock(&arg->tid_reported_mutex);
pthread_mutex_lock(&arg->terminate_thread_mutex);
while (!arg->terminate_thread)
pthread_cond_wait(&arg->terminate_thread_cond,
&arg->terminate_thread_mutex);
pthread_mutex_unlock(&arg->terminate_thread_mutex);
return NULL;
}
void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id,
pid_t *tid) {
pthread_mutex_lock(&thread_arg.tid_reported_mutex);
thread_arg.reported_tid = -1;
ASSERT_EQ(0, pthread_create(pthread_id, NULL,
TidReporterThread,
&thread_arg));
while (thread_arg.reported_tid == -1)
pthread_cond_wait(&thread_arg.tid_reported_cond,
&thread_arg.tid_reported_mutex);
pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
*tid = thread_arg.reported_tid;
}
static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) {
std::vector<pid_t> listed_tids;
pid_t tid;
while ((tid = thread_lister->GetNextTID()) >= 0)
listed_tids.push_back(tid);
EXPECT_FALSE(thread_lister->error());
return listed_tids;
}
static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) {
std::sort(first.begin(), first.end());
std::sort(second.begin(), second.end());
return std::includes(first.begin(), first.end(),
second.begin(), second.end());
}
static bool HasElement(std::vector<pid_t> vector, pid_t element) {
return std::find(vector.begin(), vector.end(), element) != vector.end();
}
// ThreadLister's output should include the current thread's TID and the TID of
// every thread we spawned.
TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
pid_t self_tid = GetTid();
ThreadLister thread_lister(getpid());
std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
ASSERT_TRUE(HasElement(listed_tids, self_tid));
ASSERT_TRUE(Includes(listed_tids, tids_));
}
// Calling Reset() should not cause ThreadLister to forget any threads it's
// supposed to know about.
TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) {
ThreadLister thread_lister(getpid());
// Run the loop body twice, because Reset() might behave differently if called
// on a freshly created object.
for (uptr i = 0; i < 2; i++) {
thread_lister.Reset();
std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
ASSERT_TRUE(Includes(listed_tids, tids_));
}
}
// If new threads have spawned during ThreadLister object's lifetime, calling
// Reset() should cause ThreadLister to recognize their existence.
TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) {
ThreadLister thread_lister(getpid());
std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
pthread_t extra_pthread_id;
pid_t extra_tid;
SpawnTidReporter(&extra_pthread_id, &extra_tid);
// Register the new thread so it gets terminated in TearDown().
pthread_ids_.push_back(extra_pthread_id);
// It would be very bizarre if the new TID had been listed before we even
// spawned that thread, but it would also cause a false success in this test,
// so better check for that.
ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
thread_lister.Reset();
std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
}
TEST(SanitizerCommon, SetEnvTest) {
const char kEnvName[] = "ENV_FOO";
SetEnv(kEnvName, "value");
EXPECT_STREQ("value", getenv(kEnvName));
unsetenv(kEnvName);
EXPECT_EQ(0, getenv(kEnvName));
}
#if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
void *thread_self_offset_test_func(void *arg) {
bool result =
*(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
return (void *)result;
}
TEST(SanitizerLinux, ThreadSelfOffset) {
EXPECT_TRUE((bool)thread_self_offset_test_func(0));
pthread_t tid;
void *result;
ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
ASSERT_EQ(0, pthread_join(tid, &result));
EXPECT_TRUE((bool)result);
}
// libpthread puts the thread descriptor at the end of stack space.
void *thread_descriptor_size_test_func(void *arg) {
uptr descr_addr = ThreadSelf();
pthread_attr_t attr;
pthread_getattr_np(pthread_self(), &attr);
void *stackaddr;
size_t stacksize;
pthread_attr_getstack(&attr, &stackaddr, &stacksize);
return (void *)((uptr)stackaddr + stacksize - descr_addr);
}
TEST(SanitizerLinux, ThreadDescriptorSize) {
pthread_t tid;
void *result;
ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
ASSERT_EQ(0, pthread_join(tid, &result));
EXPECT_EQ((uptr)result, ThreadDescriptorSize());
}
#endif
TEST(SanitizerCommon, LibraryNameIs) {
EXPECT_FALSE(LibraryNameIs("", ""));
char full_name[256];
const char *paths[] = { "", "/", "/path/to/" };
const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
const char *base_names[] = { "lib", "lib.0", "lib-i386" };
const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
paths[i], base_names[k], suffixes[j]);
EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
<< "Full name " << full_name
<< " doesn't match base name " << base_names[k];
for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
<< "Full name " << full_name
<< " matches base name " << wrong_names[m];
}
}
}
#if defined(__mips64)
// Effectively, this is a test for ThreadDescriptorSize() which is used to
// compute ThreadSelf().
TEST(SanitizerLinux, ThreadSelfTest) {
ASSERT_EQ(pthread_self(), ThreadSelf());
}
#endif
TEST(SanitizerCommon, StartSubprocessTest) {
int pipe_fds[2];
ASSERT_EQ(0, pipe(pipe_fds));
#if SANITIZER_ANDROID
const char *shell = "/system/bin/sh";
#else
const char *shell = "/bin/sh";
#endif
const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
int pid = StartSubprocess(shell, argv,
/* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
ASSERT_GT(pid, 0);
// wait for process to finish.
while (IsProcessRunning(pid)) {
}
ASSERT_FALSE(IsProcessRunning(pid));
char buffer[256];
{
char *ptr = buffer;
uptr bytes_read;
while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
if (!bytes_read) {
break;
}
ptr += bytes_read;
}
ASSERT_EQ(5, ptr - buffer);
*ptr = 0;
}
ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
internal_close(pipe_fds[0]);
}
} // namespace __sanitizer
#endif // SANITIZER_LINUX

View File

@@ -0,0 +1,189 @@
//===-- sanitizer_list_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.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_list.h"
#include "gtest/gtest.h"
namespace __sanitizer {
struct ListItem {
ListItem *next;
};
typedef IntrusiveList<ListItem> List;
static List static_list;
static void SetList(List *l, ListItem *x = 0,
ListItem *y = 0, ListItem *z = 0) {
l->clear();
if (x) l->push_back(x);
if (y) l->push_back(y);
if (z) l->push_back(z);
}
static void CheckList(List *l, ListItem *i1, ListItem *i2 = 0, ListItem *i3 = 0,
ListItem *i4 = 0, ListItem *i5 = 0, ListItem *i6 = 0) {
if (i1) {
CHECK_EQ(l->front(), i1);
l->pop_front();
}
if (i2) {
CHECK_EQ(l->front(), i2);
l->pop_front();
}
if (i3) {
CHECK_EQ(l->front(), i3);
l->pop_front();
}
if (i4) {
CHECK_EQ(l->front(), i4);
l->pop_front();
}
if (i5) {
CHECK_EQ(l->front(), i5);
l->pop_front();
}
if (i6) {
CHECK_EQ(l->front(), i6);
l->pop_front();
}
CHECK(l->empty());
}
TEST(SanitizerCommon, IntrusiveList) {
ListItem items[6];
CHECK_EQ(static_list.size(), 0);
List l;
l.clear();
ListItem *x = &items[0];
ListItem *y = &items[1];
ListItem *z = &items[2];
ListItem *a = &items[3];
ListItem *b = &items[4];
ListItem *c = &items[5];
CHECK_EQ(l.size(), 0);
l.push_back(x);
CHECK_EQ(l.size(), 1);
CHECK_EQ(l.back(), x);
CHECK_EQ(l.front(), x);
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_front(x);
CHECK_EQ(l.size(), 1);
CHECK_EQ(l.back(), x);
CHECK_EQ(l.front(), x);
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_front(x);
l.push_front(y);
l.push_front(z);
CHECK_EQ(l.size(), 3);
CHECK_EQ(l.front(), z);
CHECK_EQ(l.back(), x);
l.CheckConsistency();
l.pop_front();
CHECK_EQ(l.size(), 2);
CHECK_EQ(l.front(), y);
CHECK_EQ(l.back(), x);
l.pop_front();
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_back(x);
l.push_back(y);
l.push_back(z);
CHECK_EQ(l.size(), 3);
CHECK_EQ(l.front(), x);
CHECK_EQ(l.back(), z);
l.CheckConsistency();
l.pop_front();
CHECK_EQ(l.size(), 2);
CHECK_EQ(l.front(), y);
CHECK_EQ(l.back(), z);
l.pop_front();
l.pop_front();
CHECK(l.empty());
l.CheckConsistency();
l.push_back(x);
l.push_back(y);
l.push_back(z);
l.extract(x, y);
CHECK_EQ(l.size(), 2);
CHECK_EQ(l.front(), x);
CHECK_EQ(l.back(), z);
l.CheckConsistency();
l.extract(x, z);
CHECK_EQ(l.size(), 1);
CHECK_EQ(l.front(), x);
CHECK_EQ(l.back(), x);
l.CheckConsistency();
l.pop_front();
CHECK(l.empty());
List l1, l2;
l1.clear();
l2.clear();
l1.append_front(&l2);
CHECK(l1.empty());
CHECK(l2.empty());
l1.append_back(&l2);
CHECK(l1.empty());
CHECK(l2.empty());
SetList(&l1, x);
CheckList(&l1, x);
SetList(&l1, x, y, z);
SetList(&l2, a, b, c);
l1.append_back(&l2);
CheckList(&l1, x, y, z, a, b, c);
CHECK(l2.empty());
SetList(&l1, x, y);
SetList(&l2);
l1.append_front(&l2);
CheckList(&l1, x, y);
CHECK(l2.empty());
}
TEST(SanitizerCommon, IntrusiveListAppendEmpty) {
ListItem i;
List l;
l.clear();
l.push_back(&i);
List l2;
l2.clear();
l.append_back(&l2);
CHECK_EQ(l.back(), &i);
CHECK_EQ(l.front(), &i);
CHECK_EQ(l.size(), 1);
l.append_front(&l2);
CHECK_EQ(l.back(), &i);
CHECK_EQ(l.front(), &i);
CHECK_EQ(l.size(), 1);
}
} // namespace __sanitizer

View File

@@ -0,0 +1,137 @@
//===-- sanitizer_mutex_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.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_pthread_wrappers.h"
#include "gtest/gtest.h"
#include <string.h>
namespace __sanitizer {
template<typename MutexType>
class TestData {
public:
explicit TestData(MutexType *mtx)
: mtx_(mtx) {
for (int i = 0; i < kSize; i++)
data_[i] = 0;
}
void Write() {
Lock l(mtx_);
T v0 = data_[0];
for (int i = 0; i < kSize; i++) {
CHECK_EQ(data_[i], v0);
data_[i]++;
}
}
void TryWrite() {
if (!mtx_->TryLock())
return;
T v0 = data_[0];
for (int i = 0; i < kSize; i++) {
CHECK_EQ(data_[i], v0);
data_[i]++;
}
mtx_->Unlock();
}
void Backoff() {
volatile T data[kSize] = {};
for (int i = 0; i < kSize; i++) {
data[i]++;
CHECK_EQ(data[i], 1);
}
}
private:
typedef GenericScopedLock<MutexType> Lock;
static const int kSize = 64;
typedef u64 T;
MutexType *mtx_;
char pad_[kCacheLineSize];
T data_[kSize];
};
const int kThreads = 8;
#if SANITIZER_DEBUG
const int kIters = 16*1024;
#else
const int kIters = 64*1024;
#endif
template<typename MutexType>
static void *lock_thread(void *param) {
TestData<MutexType> *data = (TestData<MutexType>*)param;
for (int i = 0; i < kIters; i++) {
data->Write();
data->Backoff();
}
return 0;
}
template<typename MutexType>
static void *try_thread(void *param) {
TestData<MutexType> *data = (TestData<MutexType>*)param;
for (int i = 0; i < kIters; i++) {
data->TryWrite();
data->Backoff();
}
return 0;
}
template<typename MutexType>
static void check_locked(MutexType *mtx) {
GenericScopedLock<MutexType> l(mtx);
mtx->CheckLocked();
}
TEST(SanitizerCommon, SpinMutex) {
SpinMutex mtx;
mtx.Init();
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
PTHREAD_CREATE(&threads[i], 0, lock_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, SpinMutexTry) {
SpinMutex mtx;
mtx.Init();
TestData<SpinMutex> data(&mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
PTHREAD_CREATE(&threads[i], 0, try_thread<SpinMutex>, &data);
for (int i = 0; i < kThreads; i++)
PTHREAD_JOIN(threads[i], 0);
}
TEST(SanitizerCommon, BlockingMutex) {
u64 mtxmem[1024] = {};
BlockingMutex *mtx = new(mtxmem) BlockingMutex(LINKER_INITIALIZED);
TestData<BlockingMutex> data(mtx);
pthread_t threads[kThreads];
for (int i = 0; i < kThreads; i++)
PTHREAD_CREATE(&threads[i], 0, lock_thread<BlockingMutex>, &data);
for (int i = 0; i < kThreads; i++)
PTHREAD_JOIN(threads[i], 0);
check_locked(mtx);
}
} // namespace __sanitizer

View File

@@ -0,0 +1,31 @@
//===-- sanitizer_nolibc_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 libc independence of sanitizer_common.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
#include "gtest/gtest.h"
#include <stdlib.h>
extern const char *argv0;
#if SANITIZER_LINUX && defined(__x86_64__)
TEST(SanitizerCommon, NolibcMain) {
std::string NolibcTestPath = argv0;
NolibcTestPath += "-Nolibc";
int status = system(NolibcTestPath.c_str());
EXPECT_EQ(true, WIFEXITED(status));
EXPECT_EQ(0, WEXITSTATUS(status));
}
#endif

View File

@@ -0,0 +1,19 @@
//===-- sanitizer_nolibc_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 ThreadSanitizer/AddressSanitizer runtime.
// Tests for libc independence of sanitizer_common.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_libc.h"
extern "C" void _start() {
__sanitizer::internal__exit(0);
}

View File

@@ -0,0 +1,81 @@
//===-- sanitizer_posix_test.cc -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for POSIX-specific code.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_common.h"
#include "gtest/gtest.h"
#include <pthread.h>
#include <sys/mman.h>
namespace __sanitizer {
static pthread_key_t key;
static bool destructor_executed;
extern "C"
void destructor(void *arg) {
uptr iter = reinterpret_cast<uptr>(arg);
if (iter > 1) {
ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1)));
return;
}
destructor_executed = true;
}
extern "C"
void *thread_func(void *arg) {
return reinterpret_cast<void*>(pthread_setspecific(key, arg));
}
static void SpawnThread(uptr iteration) {
destructor_executed = false;
pthread_t tid;
ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func,
reinterpret_cast<void *>(iteration)));
void *retval;
ASSERT_EQ(0, pthread_join(tid, &retval));
ASSERT_EQ(0, retval);
}
TEST(SanitizerCommon, PthreadDestructorIterations) {
ASSERT_EQ(0, pthread_key_create(&key, &destructor));
SpawnThread(GetPthreadDestructorIterations());
EXPECT_TRUE(destructor_executed);
SpawnThread(GetPthreadDestructorIterations() + 1);
EXPECT_FALSE(destructor_executed);
ASSERT_EQ(0, pthread_key_delete(key));
}
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

View File

@@ -0,0 +1,153 @@
//===-- sanitizer_printf_test.cc ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for sanitizer_printf.cc
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "gtest/gtest.h"
#include <string.h>
#include <limits.h>
namespace __sanitizer {
TEST(Printf, Basic) {
char buf[1024];
uptr len = internal_snprintf(buf, sizeof(buf),
"a%db%zdc%ue%zuf%xh%zxq%pe%sr",
(int)-1, (uptr)-2, // NOLINT
(unsigned)-4, (uptr)5, // NOLINT
(unsigned)10, (uptr)11, // NOLINT
(void*)0x123, "_string_");
EXPECT_EQ(len, strlen(buf));
std::string expectedString = "a-1b-2c4294967292e5fahbq0x";
expectedString += std::string(SANITIZER_POINTER_FORMAT_LENGTH - 3, '0');
expectedString += "123e_string_r";
EXPECT_STREQ(expectedString.c_str(), buf);
}
TEST(Printf, OverflowStr) {
char buf[] = "123456789";
uptr len = internal_snprintf(buf, 4, "%s", "abcdef"); // NOLINT
EXPECT_EQ(len, (uptr)6);
EXPECT_STREQ("abc", buf);
EXPECT_EQ(buf[3], 0);
EXPECT_EQ(buf[4], '5');
EXPECT_EQ(buf[5], '6');
EXPECT_EQ(buf[6], '7');
EXPECT_EQ(buf[7], '8');
EXPECT_EQ(buf[8], '9');
EXPECT_EQ(buf[9], 0);
}
TEST(Printf, OverflowInt) {
char buf[] = "123456789";
internal_snprintf(buf, 4, "%d", -123456789); // NOLINT
EXPECT_STREQ("-12", buf);
EXPECT_EQ(buf[3], 0);
EXPECT_EQ(buf[4], '5');
EXPECT_EQ(buf[5], '6');
EXPECT_EQ(buf[6], '7');
EXPECT_EQ(buf[7], '8');
EXPECT_EQ(buf[8], '9');
EXPECT_EQ(buf[9], 0);
}
TEST(Printf, OverflowUint) {
char buf[] = "123456789";
uptr val;
if (sizeof(val) == 4) {
val = (uptr)0x12345678;
} else {
val = (uptr)0x123456789ULL;
}
internal_snprintf(buf, 4, "a%zx", val); // NOLINT
EXPECT_STREQ("a12", buf);
EXPECT_EQ(buf[3], 0);
EXPECT_EQ(buf[4], '5');
EXPECT_EQ(buf[5], '6');
EXPECT_EQ(buf[6], '7');
EXPECT_EQ(buf[7], '8');
EXPECT_EQ(buf[8], '9');
EXPECT_EQ(buf[9], 0);
}
TEST(Printf, OverflowPtr) {
char buf[] = "123456789";
void *p;
if (sizeof(p) == 4) {
p = (void*)0x1234567;
} else {
p = (void*)0x123456789ULL;
}
internal_snprintf(buf, 4, "%p", p); // NOLINT
EXPECT_STREQ("0x0", buf);
EXPECT_EQ(buf[3], 0);
EXPECT_EQ(buf[4], '5');
EXPECT_EQ(buf[5], '6');
EXPECT_EQ(buf[6], '7');
EXPECT_EQ(buf[7], '8');
EXPECT_EQ(buf[8], '9');
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];
uptr len = internal_snprintf(buf, sizeof(buf), fmt, arg1, arg2);
char buf2[1024];
snprintf(buf2, sizeof(buf2), fmt, arg1, arg2);
EXPECT_EQ(len, strlen(buf));
EXPECT_STREQ(buf2, buf);
}
TEST(Printf, MinMax) {
TestAgainstLibc<int>("%d-%d", INT_MIN, INT_MAX); // NOLINT
TestAgainstLibc<unsigned>("%u-%u", 0, UINT_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
#endif
}
TEST(Printf, Padding) {
TestAgainstLibc<int>("%3d - %3d", 1, 0);
TestAgainstLibc<int>("%3d - %3d", -1, 123);
TestAgainstLibc<int>("%3d - %3d", -1, -123);
TestAgainstLibc<int>("%3d - %3d", 12, 1234);
TestAgainstLibc<int>("%3d - %3d", -12, -1234);
TestAgainstLibc<int>("%03d - %03d", 1, 0);
TestAgainstLibc<int>("%03d - %03d", -1, 123);
TestAgainstLibc<int>("%03d - %03d", -1, -123);
TestAgainstLibc<int>("%03d - %03d", 12, 1234);
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

Some files were not shown because too many files have changed in this diff Show More