forked from OSchip/llvm-project
[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:
parent
6de11a494f
commit
c47620a838
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in New Issue