[tsan] Add TSan unit test support for OS X

This patch enables building and running TSan unit tests on OS X.

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

llvm-svn: 252731
This commit is contained in:
Kuba Brecka 2015-11-11 14:53:57 +00:00
parent 6de11a494f
commit c47620a838
9 changed files with 103 additions and 40 deletions

View File

@ -24,19 +24,6 @@ function(translate_msvc_cflags out_flags msvc_flags)
set(${out_flags} "${clang_flags}" PARENT_SCOPE)
endfunction()
if (APPLE)
# On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
# the command line tools. If this is the case, we need to find the OS X
# sysroot to pass to clang.
if(NOT EXISTS /usr/include)
execute_process(COMMAND xcodebuild -version -sdk macosx Path
OUTPUT_VARIABLE OSX_SYSROOT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
endif()
endif()
# Compile a source into an object file with COMPILER_RT_TEST_COMPILER using
# a provided compile flags and dependenices.
# clang_compile(<object> <source>

View File

@ -279,6 +279,17 @@ set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64})
if(APPLE)
include(CompilerRTDarwinUtils)
# On Darwin if /usr/include doesn't exist, the user probably has Xcode but not
# the command line tools. If this is the case, we need to find the OS X
# sysroot to pass to clang.
if(NOT EXISTS /usr/include)
execute_process(COMMAND xcodebuild -version -sdk macosx Path
OUTPUT_VARIABLE OSX_SYSROOT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(OSX_SYSROOT_FLAG "-isysroot${OSX_SYSROOT}")
endif()
option(COMPILER_RT_ENABLE_IOS "Enable building for iOS - Experimental" Off)
find_darwin_sdk_dir(DARWIN_osx_SYSROOT macosx)

View File

@ -87,6 +87,12 @@ set(TSAN_HEADERS
set(TSAN_RUNTIME_LIBRARIES)
add_custom_target(tsan)
add_compiler_rt_object_libraries(RTTsan_dynamic
OS ${TSAN_SUPPORTED_OS}
ARCHS ${TSAN_SUPPORTED_ARCH}
SOURCES ${TSAN_SOURCES} ${TSAN_CXX_SOURCES}
CFLAGS ${TSAN_RTL_CFLAGS})
if(APPLE)
add_compiler_rt_runtime(clang_rt.tsan
SHARED

View File

@ -33,8 +33,7 @@ macro(tsan_compile obj_list source arch)
endmacro()
macro(add_tsan_unittest testname)
# Build unit tests only for 64-bit Linux.
if(UNIX AND NOT APPLE)
if(UNIX)
foreach(arch ${TSAN_SUPPORTED_ARCH})
cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN})
set(TEST_OBJECTS)
@ -46,15 +45,38 @@ macro(add_tsan_unittest testname)
if(NOT COMPILER_RT_STANDALONE_BUILD)
list(APPEND TEST_DEPS tsan)
endif()
# FIXME: Looks like we should link TSan with just-built runtime,
# and not rely on -fsanitize=thread, as these tests are essentially
# unit tests.
add_compiler_rt_test(TsanUnitTests ${testname}
OBJECTS ${TEST_OBJECTS}
DEPS ${TEST_DEPS}
LINK_FLAGS ${TARGET_LINK_FLAGS}
-fsanitize=thread
-lstdc++ -lm)
if(NOT APPLE)
# FIXME: Looks like we should link TSan with just-built runtime,
# and not rely on -fsanitize=thread, as these tests are essentially
# unit tests.
add_compiler_rt_test(TsanUnitTests ${testname}
OBJECTS ${TEST_OBJECTS}
DEPS ${TEST_DEPS}
LINK_FLAGS ${TARGET_LINK_FLAGS}
-fsanitize=thread
-lstdc++ -lm)
else()
set(TSAN_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTTsan_dynamic.osx>
$<TARGET_OBJECTS:RTInterception.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>
$<TARGET_OBJECTS:RTUbsan.osx>)
set(TSAN_TEST_RUNTIME RTTsanTest.${testname}.${arch})
add_library(${TSAN_TEST_RUNTIME} STATIC ${TSAN_TEST_RUNTIME_OBJECTS})
set_target_properties(${TSAN_TEST_RUNTIME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND TEST_OBJECTS lib${TSAN_TEST_RUNTIME}.a)
list(APPEND TEST_DEPS ${TSAN_TEST_RUNTIME})
# Intentionally do *not* link with `-fsanitize=thread`. We already link
# against a static version of the runtime, and we don't want the dynamic
# one.
add_compiler_rt_test(TsanUnitTests "${testname}-${arch}-Test"
OBJECTS ${TEST_OBJECTS}
DEPS ${TEST_DEPS}
LINK_FLAGS ${TARGET_LINK_FLAGS}
-lc++)
endif()
endforeach()
endif()
endmacro()

View File

@ -7,7 +7,7 @@ set(TSAN_RTL_TEST_SOURCES
tsan_test.cc
tsan_thread.cc)
if(UNIX AND NOT APPLE)
if(UNIX)
list(APPEND TSAN_RTL_TEST_SOURCES tsan_test_util_linux.cc)
endif()

View File

@ -47,6 +47,13 @@ int run_tests(int argc, char **argv) {
const char *argv0;
#ifdef __APPLE__
// On Darwin, turns off symbolication and crash logs to make tests faster.
extern "C" const char* __tsan_default_options() {
return "symbolize=false:abort_on_error=0";
}
#endif
int main(int argc, char **argv) {
argv0 = argv[0];
return run_tests(argc, argv);

View File

@ -31,7 +31,15 @@ class MemLoc {
class Mutex {
public:
enum Type { Normal, Spin, RW };
enum Type {
Normal,
RW,
#ifndef APPLE
Spin
#else
Spin = Normal
#endif
};
explicit Mutex(Type type = Normal);
~Mutex();

View File

@ -1,4 +1,3 @@
//===-- tsan_test_util_linux.cc -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
@ -10,7 +9,7 @@
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// Test utils, Linux and FreeBSD implementation.
// Test utils, Linux, FreeBSD and Darwin implementation.
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_atomic.h"
@ -34,8 +33,20 @@ static __thread bool expect_report;
static __thread bool expect_report_reported;
static __thread ReportType expect_report_type;
extern "C" void *__interceptor_memcpy(void*, const void*, uptr);
extern "C" void *__interceptor_memset(void*, int, uptr);
#ifdef __APPLE__
#define __interceptor_memcpy wrap_memcpy
#define __interceptor_memset wrap_memset
#define __interceptor_pthread_create wrap_pthread_create
#define __interceptor_pthread_join wrap_pthread_join
#endif
extern "C" void *__interceptor_memcpy(void *, const void *, uptr);
extern "C" void *__interceptor_memset(void *, int, uptr);
extern "C" int __interceptor_pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg);
extern "C" int __interceptor_pthread_join(pthread_t thread, void **value_ptr);
static void *BeforeInitThread(void *param) {
(void)param;
@ -52,8 +63,8 @@ void TestMutexBeforeInit() {
pthread_mutex_unlock(&mtx);
pthread_mutex_destroy(&mtx);
pthread_t thr;
pthread_create(&thr, 0, BeforeInitThread, 0);
pthread_join(thr, 0);
__interceptor_pthread_create(&thr, 0, BeforeInitThread, 0);
__interceptor_pthread_join(thr, 0);
atexit(AtExit);
}
@ -106,8 +117,10 @@ void Mutex::Init() {
alive_ = true;
if (type_ == Normal)
CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
#ifndef __APPLE__
else if (type_ == Spin)
CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
#endif
else if (type_ == RW)
CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
else
@ -127,8 +140,10 @@ void Mutex::Destroy() {
alive_ = false;
if (type_ == Normal)
CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
#ifndef __APPLE__
else if (type_ == Spin)
CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
#endif
else if (type_ == RW)
CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
}
@ -137,8 +152,10 @@ void Mutex::Lock() {
CHECK(alive_);
if (type_ == Normal)
CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
#ifndef __APPLE__
else if (type_ == Spin)
CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
#endif
else if (type_ == RW)
CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
}
@ -147,8 +164,10 @@ bool Mutex::TryLock() {
CHECK(alive_);
if (type_ == Normal)
return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
#ifndef __APPLE__
else if (type_ == Spin)
return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
#endif
else if (type_ == RW)
return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
return false;
@ -158,8 +177,10 @@ void Mutex::Unlock() {
CHECK(alive_);
if (type_ == Normal)
CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
#ifndef __APPLE__
else if (type_ == Spin)
CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
#endif
else if (type_ == RW)
CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
}
@ -263,7 +284,7 @@ void ScopedThread::Impl::HandleEvent(Event *ev) {
}
}
CHECK_NE(tsan_mop, 0);
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__APPLE__)
const int ErrCode = ESOCKTNOSUPPORT;
#else
const int ErrCode = ECHRNG;
@ -327,7 +348,7 @@ void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
for (;;) {
Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire);
if (ev == 0) {
pthread_yield();
sched_yield();
continue;
}
if (ev->type == Event::SHUTDOWN) {
@ -348,7 +369,7 @@ void ScopedThread::Impl::send(Event *e) {
CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0);
atomic_store(&event, (uintptr_t)e, memory_order_release);
while (atomic_load(&event, memory_order_acquire) != 0)
pthread_yield();
sched_yield();
}
}
@ -362,7 +383,7 @@ ScopedThread::ScopedThread(bool detached, bool main) {
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, detached);
pthread_attr_setstacksize(&attr, 64*1024);
pthread_create(&impl_->thread, &attr,
__interceptor_pthread_create(&impl_->thread, &attr,
ScopedThread::Impl::ScopedThreadCallback, impl_);
}
}
@ -372,7 +393,7 @@ ScopedThread::~ScopedThread() {
Event event(Event::SHUTDOWN);
impl_->send(&event);
if (!impl_->detached)
pthread_join(impl_->thread, 0);
__interceptor_pthread_join(impl_->thread, 0);
}
delete impl_;
}

View File

@ -13,6 +13,7 @@
#include "tsan_clock.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"
#include <sys/time.h>
#include <time.h>
namespace __tsan {
@ -416,9 +417,9 @@ static bool ClockFuzzer(bool printing) {
}
TEST(Clock, Fuzzer) {
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
int seed = ts.tv_sec + ts.tv_nsec;
struct timeval tv;
gettimeofday(&tv, NULL);
int seed = tv.tv_sec + tv.tv_usec;
printf("seed=%d\n", seed);
srand(seed);
if (!ClockFuzzer(false)) {