aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-26 19:24:20 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-26 19:24:20 +0000
commit2953104c9a262728031dc518429d15b969dd6028 (patch)
treed4fff23823637f2256cedf634a2be262862ea90f
parentf351c8a560ddc5b5df9ee5ba4ccc1cfb9029146d (diff)
downloadsrc-2953104c9a262728031dc518429d15b969dd6028.tar.gz
src-2953104c9a262728031dc518429d15b969dd6028.zip
Vendor import of compiler-rt trunk r301441:vendor/compiler-rt/compiler-rt-trunk-r301441
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=317449 svn path=/vendor/compiler-rt/compiler-rt-trunk-r301441/; revision=317450; tag=vendor/compiler-rt/compiler-rt-trunk-r301441
-rw-r--r--include/sanitizer/tsan_interface.h15
-rw-r--r--lib/builtins/CMakeLists.txt9
-rw-r--r--lib/builtins/emutls.c294
-rw-r--r--lib/lsan/lsan_allocator.h2
-rw-r--r--lib/lsan/lsan_common.cc11
-rw-r--r--lib/lsan/lsan_common.h3
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_local_cache.h32
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc4
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h2
-rw-r--r--lib/scudo/scudo_allocator.cpp62
-rw-r--r--lib/tsan/rtl/tsan_external.cc31
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc4
-rw-r--r--lib/tsan/rtl/tsan_interceptors.h2
-rw-r--r--lib/tsan/rtl/tsan_report.cc4
-rw-r--r--lib/tsan/rtl/tsan_rtl.h1
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc2
-rw-r--r--test/CMakeLists.txt82
-rw-r--r--test/asan/TestCases/Linux/read_binary_name_regtest.c1
-rw-r--r--test/asan/TestCases/Linux/textdomain.c10
-rw-r--r--test/asan/TestCases/Posix/strchr.c4
-rw-r--r--test/asan/TestCases/Windows/dll_global_dead_strip.c4
-rw-r--r--test/asan/TestCases/Windows/fuse-lld.cc2
-rw-r--r--test/asan/TestCases/Windows/global_dead_strip.c4
-rwxr-xr-xtest/asan/android_commands/android_run.py5
-rw-r--r--test/cfi/CMakeLists.txt62
-rw-r--r--test/cfi/create-derivers.test9
-rw-r--r--test/cfi/cross-dso/icall/dlopen.cpp (renamed from test/cfi/cross-dso/dlopen.cpp)2
-rw-r--r--test/cfi/cross-dso/icall/lit.local.cfg3
-rw-r--r--test/cfi/cross-dso/stats.cpp4
-rw-r--r--test/cfi/icall/lit.local.cfg3
-rw-r--r--test/cfi/lit.cfg4
-rw-r--r--test/cfi/lit.site.cfg.in3
-rw-r--r--test/lit.common.cfg16
-rw-r--r--test/lit.common.configured.in2
-rw-r--r--test/lsan/lit.common.cfg5
-rw-r--r--test/safestack/lit.cfg2
-rw-r--r--test/tsan/Darwin/deadlock.mm47
-rw-r--r--test/tsan/Darwin/debug_external.cc2
-rw-r--r--test/tsan/Darwin/external-dups.cc58
-rw-r--r--test/tsan/Darwin/external-ignore-noninstrumented.cc19
-rw-r--r--test/tsan/Darwin/external-lib.cc68
-rw-r--r--test/tsan/Darwin/external-noninstrumented-module.cc27
-rw-r--r--test/tsan/Darwin/external.cc78
-rw-r--r--test/tsan/test.h2
-rw-r--r--test/tsan/unaligned_race.cc23
45 files changed, 728 insertions, 301 deletions
diff --git a/include/sanitizer/tsan_interface.h b/include/sanitizer/tsan_interface.h
index 34b74d537e0c..45e54f7581a1 100644
--- a/include/sanitizer/tsan_interface.h
+++ b/include/sanitizer/tsan_interface.h
@@ -114,6 +114,21 @@ void __tsan_mutex_post_signal(void *addr, unsigned flags);
void __tsan_mutex_pre_divert(void *addr, unsigned flags);
void __tsan_mutex_post_divert(void *addr, unsigned flags);
+// External race detection API.
+// Can be used by non-instrumented libraries to detect when their objects are
+// being used in an unsafe manner.
+// - __tsan_external_read/__tsan_external_write annotates the logical reads
+// and writes of the object at the specified address. 'caller_pc' should
+// be the PC of the library user, which the library can obtain with e.g.
+// `__builtin_return_address(0)`.
+// - __tsan_external_register_tag registers a 'tag' with the specified name,
+// which is later used in read/write annotations to denote the object type
+// - __tsan_external_assign_tag can optionally mark a heap object with a tag
+void *__tsan_external_register_tag(const char *object_type);
+void __tsan_external_assign_tag(void *addr, void *tag);
+void __tsan_external_read(void *addr, void *caller_pc, void *tag);
+void __tsan_external_write(void *addr, void *caller_pc, void *tag);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 161487e703d7..c30d9b3633fe 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -164,7 +164,8 @@ set(GENERIC_SOURCES
udivti3.c
umoddi3.c
umodsi3.c
- umodti3.c)
+ umodti3.c
+ emutls.c)
option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN
"Skip the atomic builtin (this may be needed if system headers are unavailable)"
@@ -187,12 +188,6 @@ if(APPLE)
atomic_thread_fence.c)
endif()
-if(NOT WIN32 OR MINGW)
- set(GENERIC_SOURCES
- ${GENERIC_SOURCES}
- emutls.c)
-endif()
-
if (HAVE_UNWIND_H)
set(GENERIC_SOURCES
${GENERIC_SOURCES}
diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c
index eccbf53366e3..e8d5ddb22011 100644
--- a/lib/builtins/emutls.c
+++ b/lib/builtins/emutls.c
@@ -7,7 +7,6 @@
*
* ===----------------------------------------------------------------------===
*/
-#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -15,6 +14,23 @@
#include "int_lib.h"
#include "int_util.h"
+typedef struct emutls_address_array {
+ uintptr_t size; /* number of elements in the 'data' array */
+ void* data[];
+} emutls_address_array;
+
+static void emutls_shutdown(emutls_address_array *array);
+
+#ifndef _WIN32
+
+#include <pthread.h>
+
+static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t emutls_pthread_key;
+
+typedef unsigned int gcc_word __attribute__((mode(word)));
+typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
+
/* Default is not to use posix_memalign, so systems like Android
* can use thread local data without heavier POSIX memory allocators.
*/
@@ -22,26 +38,6 @@
#define EMUTLS_USE_POSIX_MEMALIGN 0
#endif
-/* For every TLS variable xyz,
- * there is one __emutls_control variable named __emutls_v.xyz.
- * If xyz has non-zero initial value, __emutls_v.xyz's "value"
- * will point to __emutls_t.xyz, which has the initial value.
- */
-typedef unsigned int gcc_word __attribute__((mode(word)));
-typedef struct __emutls_control {
- /* Must use gcc_word here, instead of size_t, to match GCC. When
- gcc_word is larger than size_t, the upper extra bits are all
- zeros. We can use variables of size_t to operate on size and
- align. */
- gcc_word size; /* size of the object in bytes */
- gcc_word align; /* alignment of the object in bytes */
- union {
- uintptr_t index; /* data[index-1] is the object address */
- void* address; /* object address, when in single thread env */
- } object;
- void* value; /* null or non-zero initial value for the object */
-} __emutls_control;
-
static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
void *base;
#if EMUTLS_USE_POSIX_MEMALIGN
@@ -50,7 +46,7 @@ static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
#else
#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
char* object;
- if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
+ if ((object = (char*)malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
abort();
base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
& ~(uintptr_t)(align - 1));
@@ -69,10 +65,207 @@ static __inline void emutls_memalign_free(void *base) {
#endif
}
+static void emutls_key_destructor(void* ptr) {
+ emutls_shutdown((emutls_address_array*)ptr);
+ free(ptr);
+}
+
+static __inline void emutls_init(void) {
+ if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
+ abort();
+}
+
+static __inline void emutls_init_once(void) {
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, emutls_init);
+}
+
+static __inline void emutls_lock() {
+ pthread_mutex_lock(&emutls_mutex);
+}
+
+static __inline void emutls_unlock() {
+ pthread_mutex_unlock(&emutls_mutex);
+}
+
+static __inline void emutls_setspecific(emutls_address_array *value) {
+ pthread_setspecific(emutls_pthread_key, (void*) value);
+}
+
+static __inline emutls_address_array* emutls_getspecific() {
+ return (emutls_address_array*) pthread_getspecific(emutls_pthread_key);
+}
+
+#else
+
+#include <Windows.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <assert.h>
+#include <immintrin.h>
+
+static LPCRITICAL_SECTION emutls_mutex;
+static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES;
+
+typedef uintptr_t gcc_word;
+typedef void * gcc_pointer;
+
+static void win_error(DWORD last_err, const char *hint) {
+ char *buffer = NULL;
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) {
+ fprintf(stderr, "Windows error: %s\n", buffer);
+ } else {
+ fprintf(stderr, "Unkown Windows error: %s\n", hint);
+ }
+ LocalFree(buffer);
+}
+
+static __inline void win_abort(DWORD last_err, const char *hint) {
+ win_error(last_err, hint);
+ abort();
+}
+
+static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
+ void *base = _aligned_malloc(size, align);
+ if (!base)
+ win_abort(GetLastError(), "_aligned_malloc");
+ return base;
+}
+
+static __inline void emutls_memalign_free(void *base) {
+ _aligned_free(base);
+}
+
+static void emutls_exit(void) {
+ if (emutls_mutex) {
+ DeleteCriticalSection(emutls_mutex);
+ _aligned_free(emutls_mutex);
+ emutls_mutex = NULL;
+ }
+ if (emutls_tls_index != TLS_OUT_OF_INDEXES) {
+ emutls_shutdown((emutls_address_array*)TlsGetValue(emutls_tls_index));
+ TlsFree(emutls_tls_index);
+ emutls_tls_index = TLS_OUT_OF_INDEXES;
+ }
+}
+
+#pragma warning (push)
+#pragma warning (disable : 4100)
+static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) {
+ emutls_mutex = (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16);
+ if (!emutls_mutex) {
+ win_error(GetLastError(), "_aligned_malloc");
+ return FALSE;
+ }
+ InitializeCriticalSection(emutls_mutex);
+
+ emutls_tls_index = TlsAlloc();
+ if (emutls_tls_index == TLS_OUT_OF_INDEXES) {
+ emutls_exit();
+ win_error(GetLastError(), "TlsAlloc");
+ return FALSE;
+ }
+ atexit(&emutls_exit);
+ return TRUE;
+}
+
+static __inline void emutls_init_once(void) {
+ static INIT_ONCE once;
+ InitOnceExecuteOnce(&once, emutls_init, NULL, NULL);
+}
+
+static __inline void emutls_lock() {
+ EnterCriticalSection(emutls_mutex);
+}
+
+static __inline void emutls_unlock() {
+ LeaveCriticalSection(emutls_mutex);
+}
+
+static __inline void emutls_setspecific(emutls_address_array *value) {
+ if (TlsSetValue(emutls_tls_index, (LPVOID) value) == 0)
+ win_abort(GetLastError(), "TlsSetValue");
+}
+
+static __inline emutls_address_array* emutls_getspecific() {
+ LPVOID value = TlsGetValue(emutls_tls_index);
+ if (value == NULL) {
+ const DWORD err = GetLastError();
+ if (err != ERROR_SUCCESS)
+ win_abort(err, "TlsGetValue");
+ }
+ return (emutls_address_array*) value;
+}
+
+/* Provide atomic load/store functions for emutls_get_index if built with MSVC.
+ */
+#if !defined(__ATOMIC_RELEASE)
+
+enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 };
+
+static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) {
+ assert(type == __ATOMIC_ACQUIRE);
+#ifdef _WIN64
+ return (uintptr_t) _load_be_u64(ptr);
+#else
+ return (uintptr_t) _load_be_u32(ptr);
+#endif
+}
+
+static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {
+ assert(type == __ATOMIC_RELEASE);
+#ifdef _WIN64
+ _store_be_u64(ptr, val);
+#else
+ _store_be_u32(ptr, val);
+#endif
+}
+
+#endif
+
+#pragma warning (pop)
+
+#endif
+
+static size_t emutls_num_object = 0; /* number of allocated TLS objects */
+
+/* Free the allocated TLS data
+ */
+static void emutls_shutdown(emutls_address_array *array) {
+ if (array) {
+ uintptr_t i;
+ for (i = 0; i < array->size; ++i) {
+ if (array->data[i])
+ emutls_memalign_free(array->data[i]);
+ }
+ }
+}
+
+/* For every TLS variable xyz,
+ * there is one __emutls_control variable named __emutls_v.xyz.
+ * If xyz has non-zero initial value, __emutls_v.xyz's "value"
+ * will point to __emutls_t.xyz, which has the initial value.
+ */
+typedef struct __emutls_control {
+ /* Must use gcc_word here, instead of size_t, to match GCC. When
+ gcc_word is larger than size_t, the upper extra bits are all
+ zeros. We can use variables of size_t to operate on size and
+ align. */
+ gcc_word size; /* size of the object in bytes */
+ gcc_word align; /* alignment of the object in bytes */
+ union {
+ uintptr_t index; /* data[index-1] is the object address */
+ void* address; /* object address, when in single thread env */
+ } object;
+ void* value; /* null or non-zero initial value for the object */
+} __emutls_control;
+
/* Emulated TLS objects are always allocated at run-time. */
static __inline void *emutls_allocate_object(__emutls_control *control) {
/* Use standard C types, check with gcc's emutls.o. */
- typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
@@ -93,45 +286,19 @@ static __inline void *emutls_allocate_object(__emutls_control *control) {
return base;
}
-static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static size_t emutls_num_object = 0; /* number of allocated TLS objects */
-
-typedef struct emutls_address_array {
- uintptr_t size; /* number of elements in the 'data' array */
- void* data[];
-} emutls_address_array;
-
-static pthread_key_t emutls_pthread_key;
-
-static void emutls_key_destructor(void* ptr) {
- emutls_address_array* array = (emutls_address_array*)ptr;
- uintptr_t i;
- for (i = 0; i < array->size; ++i) {
- if (array->data[i])
- emutls_memalign_free(array->data[i]);
- }
- free(ptr);
-}
-
-static void emutls_init(void) {
- if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
- abort();
-}
/* Returns control->object.index; set index if not allocated yet. */
static __inline uintptr_t emutls_get_index(__emutls_control *control) {
uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
if (!index) {
- static pthread_once_t once = PTHREAD_ONCE_INIT;
- pthread_once(&once, emutls_init);
- pthread_mutex_lock(&emutls_mutex);
+ emutls_init_once();
+ emutls_lock();
index = control->object.index;
if (!index) {
index = ++emutls_num_object;
__atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
}
- pthread_mutex_unlock(&emutls_mutex);
+ emutls_unlock();
}
return index;
}
@@ -142,7 +309,7 @@ static __inline void emutls_check_array_set_size(emutls_address_array *array,
if (array == NULL)
abort();
array->size = size;
- pthread_setspecific(emutls_pthread_key, (void*)array);
+ emutls_setspecific(array);
}
/* Returns the new 'data' array size, number of elements,
@@ -156,22 +323,29 @@ static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
}
+/* Returns the size in bytes required for an emutls_address_array with
+ * N number of elements for data field.
+ */
+static __inline uintptr_t emutls_asize(uintptr_t N) {
+ return N * sizeof(void *) + sizeof(emutls_address_array);
+}
+
/* Returns the thread local emutls_address_array.
* Extends its size if necessary to hold address at index.
*/
static __inline emutls_address_array *
emutls_get_address_array(uintptr_t index) {
- emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
+ emutls_address_array* array = emutls_getspecific();
if (array == NULL) {
uintptr_t new_size = emutls_new_data_array_size(index);
- array = malloc(new_size * sizeof(void *) + sizeof(emutls_address_array));
+ array = (emutls_address_array*) malloc(emutls_asize(new_size));
if (array)
memset(array->data, 0, new_size * sizeof(void*));
emutls_check_array_set_size(array, new_size);
} else if (index > array->size) {
uintptr_t orig_size = array->size;
uintptr_t new_size = emutls_new_data_array_size(index);
- array = realloc(array, new_size * sizeof(void *) + sizeof(emutls_address_array));
+ array = (emutls_address_array*) realloc(array, emutls_asize(new_size));
if (array)
memset(array->data + orig_size, 0,
(new_size - orig_size) * sizeof(void*));
@@ -182,8 +356,8 @@ emutls_get_address_array(uintptr_t index) {
void* __emutls_get_address(__emutls_control* control) {
uintptr_t index = emutls_get_index(control);
- emutls_address_array* array = emutls_get_address_array(index);
- if (array->data[index - 1] == NULL)
- array->data[index - 1] = emutls_allocate_object(control);
- return array->data[index - 1];
+ emutls_address_array* array = emutls_get_address_array(index--);
+ if (array->data[index] == NULL)
+ array->data[index] = emutls_allocate_object(control);
+ return array->data[index];
}
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
index e5def17d4ee9..fad5adb01a7f 100644
--- a/lib/lsan/lsan_allocator.h
+++ b/lib/lsan/lsan_allocator.h
@@ -59,7 +59,7 @@ typedef CompactSizeClassMap SizeClassMap;
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
PrimaryAllocator;
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(__powerpc64__)
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = 0x600000000000ULL;
static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 200f16a594fa..a6b3453f5a0b 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -70,12 +70,13 @@ static const char kSuppressionLeak[] = "leak";
static const char *kSuppressionTypes[] = { kSuppressionLeak };
static const char kStdSuppressions[] =
#if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
- // The actual string allocation happens here (for more details refer to the
- // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT definition).
- "leak:*_dl_map_object_deps*";
-#else
- "";
+ // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+ // definition.
+ "leak:*pthread_exit*\n"
#endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+ // TLS leak in some glibc versions, described in
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=12650.
+ "leak:*tls_get_addr*\n";
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index 121b9c082983..beb31d6f40e4 100644
--- a/lib/lsan/lsan_common.h
+++ b/lib/lsan/lsan_common.h
@@ -32,7 +32,8 @@
// new architecture inside sanitizer library.
#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \
(SANITIZER_WORDSIZE == 64) && \
- (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
+ (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \
+ defined(__powerpc64__))
#define CAN_SANITIZE_LEAKS 1
#elif defined(__i386__) && \
(SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC)
diff --git a/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/lib/sanitizer_common/sanitizer_allocator_local_cache.h
index d6c66604ec86..b3729bf55dbb 100644
--- a/lib/sanitizer_common/sanitizer_allocator_local_cache.h
+++ b/lib/sanitizer_common/sanitizer_allocator_local_cache.h
@@ -180,6 +180,7 @@ struct SizeClassAllocator32LocalCache {
uptr count;
uptr max_count;
uptr class_size;
+ uptr class_id_for_transfer_batch;
void *batch[2 * TransferBatch::kMaxNumCached];
};
PerClass per_class_[kNumClasses];
@@ -188,32 +189,31 @@ struct SizeClassAllocator32LocalCache {
void InitCache() {
if (per_class_[1].max_count)
return;
+ // TransferBatch class is declared in SizeClassAllocator.
+ uptr class_id_for_transfer_batch =
+ SizeClassMap::ClassID(sizeof(TransferBatch));
for (uptr i = 0; i < kNumClasses; i++) {
PerClass *c = &per_class_[i];
- c->max_count = 2 * TransferBatch::MaxCached(i);
+ uptr max_cached = TransferBatch::MaxCached(i);
+ c->max_count = 2 * max_cached;
c->class_size = Allocator::ClassIdToSize(i);
+ // We transfer chunks between central and thread-local free lists in
+ // batches. For small size classes we allocate batches separately. For
+ // large size classes we may use one of the chunks to store the batch.
+ // sizeof(TransferBatch) must be a power of 2 for more efficient
+ // allocation.
+ c->class_id_for_transfer_batch = (c->class_size <
+ TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ?
+ class_id_for_transfer_batch : 0;
}
}
- // TransferBatch class is declared in SizeClassAllocator.
- // We transfer chunks between central and thread-local free lists in batches.
- // For small size classes we allocate batches separately.
- // For large size classes we may use one of the chunks to store the batch.
- // sizeof(TransferBatch) must be a power of 2 for more efficient allocation.
- static uptr SizeClassForTransferBatch(uptr class_id) {
- if (Allocator::ClassIdToSize(class_id) <
- TransferBatch::AllocationSizeRequiredForNElements(
- TransferBatch::MaxCached(class_id)))
- return SizeClassMap::ClassID(sizeof(TransferBatch));
- return 0;
- }
-
// Returns a TransferBatch suitable for class_id.
// For small size classes allocates the batch from the allocator.
// For large size classes simply returns b.
TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator,
TransferBatch *b) {
- if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
+ if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch)
return (TransferBatch*)Allocate(allocator, batch_class_id);
return b;
}
@@ -223,7 +223,7 @@ struct SizeClassAllocator32LocalCache {
// Does notthing for large size classes.
void DestroyBatch(uptr class_id, SizeClassAllocator *allocator,
TransferBatch *b) {
- if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
+ if (uptr batch_class_id = per_class_[class_id].class_id_for_transfer_batch)
Deallocate(allocator, batch_class_id, b);
}
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index d1c793c551f7..4fe1ac8f9da7 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -304,7 +304,7 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) {
INTERCEPTOR(char*, textdomain, const char *domainname) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
- COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+ if (domainname) COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
char *domain = REAL(textdomain)(domainname);
if (domain) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
@@ -3330,7 +3330,7 @@ INTERCEPTOR(char *, strerror, int errnum) {
// * GNU version returns message pointer, which points to either buf or some
// static storage.
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \
- SANITIZER_MAC
+ SANITIZER_MAC || SANITIZER_ANDROID
// POSIX version. Spec is not clear on whether buf is NULL-terminated.
// At least on OSX, buf contents are valid even when the call fails.
INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) {
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index c2d9f2cd3762..c6f6a211573c 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -83,7 +83,7 @@ namespace __sanitizer {
#elif defined(__mips__)
const unsigned struct_kernel_stat_sz =
SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) :
- FIRST_32_SECOND_64(144, 216);
+ FIRST_32_SECOND_64(160, 216);
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__s390__) && !defined(__s390x__)
const unsigned struct_kernel_stat_sz = 64;
diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp
index 9812fc0f59f8..e89e09223ff8 100644
--- a/lib/scudo/scudo_allocator.cpp
+++ b/lib/scudo/scudo_allocator.cpp
@@ -460,6 +460,38 @@ struct ScudoAllocator {
return UserPtr;
}
+ // Place a chunk in the quarantine. In the event of a zero-sized quarantine,
+ // we directly deallocate the chunk, otherwise the flow would lead to the
+ // chunk being checksummed twice, once before Put and once in Recycle, with
+ // no additional security value.
+ void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header,
+ uptr Size) {
+ bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0);
+ if (BypassQuarantine) {
+ Chunk->eraseHeader();
+ void *Ptr = Chunk->getAllocBeg(Header);
+ if (LIKELY(!ThreadTornDown)) {
+ getBackendAllocator().Deallocate(&Cache, Ptr);
+ } else {
+ SpinMutexLock Lock(&FallbackMutex);
+ getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr);
+ }
+ } else {
+ UnpackedHeader NewHeader = *Header;
+ NewHeader.State = ChunkQuarantine;
+ Chunk->compareExchangeHeader(&NewHeader, Header);
+ if (LIKELY(!ThreadTornDown)) {
+ AllocatorQuarantine.Put(&ThreadQuarantineCache,
+ QuarantineCallback(&Cache), Chunk, Size);
+ } else {
+ SpinMutexLock l(&FallbackMutex);
+ AllocatorQuarantine.Put(&FallbackQuarantineCache,
+ QuarantineCallback(&FallbackAllocatorCache),
+ Chunk, Size);
+ }
+ }
+ }
+
// Deallocates a Chunk, which means adding it to the delayed free list (or
// Quarantine).
void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) {
@@ -499,24 +531,12 @@ struct ScudoAllocator {
}
}
- UnpackedHeader NewHeader = OldHeader;
- NewHeader.State = ChunkQuarantine;
- Chunk->compareExchangeHeader(&NewHeader, &OldHeader);
-
// If a small memory amount was allocated with a larger alignment, we want
// to take that into account. Otherwise the Quarantine would be filled with
- // tiny chunks, taking a lot of VA memory. This an approximation of the
+ // tiny chunks, taking a lot of VA memory. This is an approximation of the
// usable size, that allows us to not call GetActuallyAllocatedSize.
uptr LiableSize = Size + (OldHeader.Offset << MinAlignment);
- if (LIKELY(!ThreadTornDown)) {
- AllocatorQuarantine.Put(&ThreadQuarantineCache,
- QuarantineCallback(&Cache), Chunk, LiableSize);
- } else {
- SpinMutexLock l(&FallbackMutex);
- AllocatorQuarantine.Put(&FallbackQuarantineCache,
- QuarantineCallback(&FallbackAllocatorCache),
- Chunk, LiableSize);
- }
+ quarantineOrDeallocateChunk(Chunk, &OldHeader, LiableSize);
}
// Reallocates a chunk. We can save on a new allocation if the new requested
@@ -541,11 +561,11 @@ struct ScudoAllocator {
OldPtr);
}
uptr UsableSize = Chunk->getUsableSize(&OldHeader);
- UnpackedHeader NewHeader = OldHeader;
// The new size still fits in the current chunk, and the size difference
// is reasonable.
if (NewSize <= UsableSize &&
(UsableSize - NewSize) < (SizeClassMap::kMaxSize / 2)) {
+ UnpackedHeader NewHeader = OldHeader;
NewHeader.SizeOrUnusedBytes =
OldHeader.FromPrimary ? NewSize : UsableSize - NewSize;
Chunk->compareExchangeHeader(&NewHeader, &OldHeader);
@@ -558,17 +578,7 @@ struct ScudoAllocator {
uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes :
UsableSize - OldHeader.SizeOrUnusedBytes;
memcpy(NewPtr, OldPtr, Min(NewSize, OldSize));
- NewHeader.State = ChunkQuarantine;
- Chunk->compareExchangeHeader(&NewHeader, &OldHeader);
- if (LIKELY(!ThreadTornDown)) {
- AllocatorQuarantine.Put(&ThreadQuarantineCache,
- QuarantineCallback(&Cache), Chunk, UsableSize);
- } else {
- SpinMutexLock l(&FallbackMutex);
- AllocatorQuarantine.Put(&FallbackQuarantineCache,
- QuarantineCallback(&FallbackAllocatorCache),
- Chunk, UsableSize);
- }
+ quarantineOrDeallocateChunk(Chunk, &OldHeader, UsableSize);
}
return NewPtr;
}
diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc
index dc8ec62322ce..88468e406651 100644
--- a/lib/tsan/rtl/tsan_external.cc
+++ b/lib/tsan/rtl/tsan_external.cc
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "tsan_rtl.h"
+#include "tsan_interceptors.h"
namespace __tsan {
@@ -29,6 +30,20 @@ const char *GetObjectTypeFromTag(uptr tag) {
return registered_tags[tag];
}
+typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int);
+void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) {
+ CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+ ThreadState *thr = cur_thread();
+ thr->external_tag = (uptr)tag;
+ if (caller_pc) FuncEntry(thr, (uptr)caller_pc);
+ bool in_ignored_lib;
+ if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) {
+ access(thr, CALLERPC, (uptr)addr, kSizeLog1);
+ }
+ if (caller_pc) FuncExit(thr);
+ thr->external_tag = 0;
+}
+
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void *__tsan_external_register_tag(const char *object_type) {
@@ -54,24 +69,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
- CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
- ThreadState *thr = cur_thread();
- thr->external_tag = (uptr)tag;
- FuncEntry(thr, (uptr)caller_pc);
- MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog8);
- FuncExit(thr);
- thr->external_tag = 0;
+ ExternalAccess(addr, caller_pc, tag, MemoryRead);
}
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
- CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
- ThreadState *thr = cur_thread();
- thr->external_tag = (uptr)tag;
- FuncEntry(thr, (uptr)caller_pc);
- MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog8);
- FuncExit(thr);
- thr->external_tag = 0;
+ ExternalAccess(addr, caller_pc, tag, MemoryWrite);
}
} // extern "C"
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index d0fd91aec234..334cc326daf6 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -210,7 +210,7 @@ struct ThreadSignalContext {
// The object is 64-byte aligned, because we want hot data to be located in
// a single cache line if possible (it's accessed in every interceptor).
static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
-static LibIgnore *libignore() {
+LibIgnore *libignore() {
return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
}
@@ -269,6 +269,7 @@ ScopedInterceptor::~ScopedInterceptor() {
void ScopedInterceptor::EnableIgnores() {
if (ignoring_) {
ThreadIgnoreBegin(thr_, pc_, false);
+ if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++;
if (in_ignored_lib_) {
DCHECK(!thr_->in_ignored_lib);
thr_->in_ignored_lib = true;
@@ -279,6 +280,7 @@ void ScopedInterceptor::EnableIgnores() {
void ScopedInterceptor::DisableIgnores() {
if (ignoring_) {
ThreadIgnoreEnd(thr_, pc_);
+ if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--;
if (in_ignored_lib_) {
DCHECK(thr_->in_ignored_lib);
thr_->in_ignored_lib = false;
diff --git a/lib/tsan/rtl/tsan_interceptors.h b/lib/tsan/rtl/tsan_interceptors.h
index 72534f4a24a6..de47466501da 100644
--- a/lib/tsan/rtl/tsan_interceptors.h
+++ b/lib/tsan/rtl/tsan_interceptors.h
@@ -19,6 +19,8 @@ class ScopedInterceptor {
bool ignoring_;
};
+LibIgnore *libignore();
+
} // namespace __tsan
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 7de00840cdbc..af5fe61761d7 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -169,7 +169,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
MopDesc(first, mop->write, mop->atomic), mop->size,
(void *)mop->addr, thread_name(thrbuf, mop->tid));
} else {
- Printf(" %s access of object %s at %p by %s",
+ Printf(" %s access of %s at %p by %s",
ExternalMopDesc(first, mop->write), object_type,
(void *)mop->addr, thread_name(thrbuf, mop->tid));
}
@@ -202,7 +202,7 @@ static void PrintLocation(const ReportLocation *loc) {
loc->heap_chunk_size, loc->heap_chunk_start,
thread_name(thrbuf, loc->tid));
} else {
- Printf(" Location is %s object of size %zu at %p allocated by %s:\n",
+ Printf(" Location is %s of size %zu at %p allocated by %s:\n",
object_type, loc->heap_chunk_size, loc->heap_chunk_start,
thread_name(thrbuf, loc->tid));
}
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 3481c31ebb1c..09c97a3a4f3d 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -381,6 +381,7 @@ struct ThreadState {
// for better performance.
int ignore_reads_and_writes;
int ignore_sync;
+ int suppress_reports;
// Go does not support ignores.
#if !SANITIZER_GO
IgnoreSet mop_ignore_set;
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index 31b9e97898b0..5cd93a184ce7 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -500,7 +500,7 @@ static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
}
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
- if (!flags()->report_bugs)
+ if (!flags()->report_bugs || thr->suppress_reports)
return false;
atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index addc579973bb..7685fb3f426f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -41,47 +41,49 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
if(COMPILER_RT_BUILD_BUILTINS)
add_subdirectory(builtins)
endif()
- if(COMPILER_RT_HAS_ASAN)
- add_subdirectory(asan)
- endif()
- if(COMPILER_RT_HAS_DFSAN)
- add_subdirectory(dfsan)
- endif()
- if (COMPILER_RT_HAS_INTERCEPTION)
- add_subdirectory(interception)
- endif()
- if(COMPILER_RT_HAS_LSAN)
- add_subdirectory(lsan)
- endif()
- if(COMPILER_RT_HAS_MSAN)
- add_subdirectory(msan)
- endif()
- if(COMPILER_RT_HAS_PROFILE)
- add_subdirectory(profile)
- endif()
- if(COMPILER_RT_HAS_SANITIZER_COMMON)
- add_subdirectory(sanitizer_common)
- endif()
- if(COMPILER_RT_HAS_TSAN)
- add_subdirectory(tsan)
- endif()
- if(COMPILER_RT_HAS_UBSAN)
- add_subdirectory(ubsan)
- endif()
- # CFI tests require diagnostic mode, which is implemented in UBSan.
- if(COMPILER_RT_HAS_UBSAN)
- add_subdirectory(cfi)
- endif()
- if(COMPILER_RT_HAS_SAFESTACK)
- add_subdirectory(safestack)
- endif()
- if(COMPILER_RT_HAS_ESAN)
- add_subdirectory(esan)
- endif()
- if(COMPILER_RT_HAS_SCUDO)
- add_subdirectory(scudo)
+ if(COMPILER_RT_BUILD_SANITIZERS)
+ if(COMPILER_RT_HAS_ASAN)
+ add_subdirectory(asan)
+ endif()
+ if(COMPILER_RT_HAS_DFSAN)
+ add_subdirectory(dfsan)
+ endif()
+ if (COMPILER_RT_HAS_INTERCEPTION)
+ add_subdirectory(interception)
+ endif()
+ if(COMPILER_RT_HAS_LSAN)
+ add_subdirectory(lsan)
+ endif()
+ if(COMPILER_RT_HAS_MSAN)
+ add_subdirectory(msan)
+ endif()
+ if(COMPILER_RT_HAS_PROFILE)
+ add_subdirectory(profile)
+ endif()
+ if(COMPILER_RT_HAS_SANITIZER_COMMON)
+ add_subdirectory(sanitizer_common)
+ endif()
+ if(COMPILER_RT_HAS_TSAN)
+ add_subdirectory(tsan)
+ endif()
+ if(COMPILER_RT_HAS_UBSAN)
+ add_subdirectory(ubsan)
+ endif()
+ # CFI tests require diagnostic mode, which is implemented in UBSan.
+ if(COMPILER_RT_HAS_UBSAN)
+ add_subdirectory(cfi)
+ endif()
+ if(COMPILER_RT_HAS_SAFESTACK)
+ add_subdirectory(safestack)
+ endif()
+ if(COMPILER_RT_HAS_ESAN)
+ add_subdirectory(esan)
+ endif()
+ if(COMPILER_RT_HAS_SCUDO)
+ add_subdirectory(scudo)
+ endif()
endif()
- if(COMPILER_RT_HAS_XRAY)
+ if(COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY)
add_subdirectory(xray)
endif()
endif()
diff --git a/test/asan/TestCases/Linux/read_binary_name_regtest.c b/test/asan/TestCases/Linux/read_binary_name_regtest.c
index b09096c89cb7..41302567752c 100644
--- a/test/asan/TestCases/Linux/read_binary_name_regtest.c
+++ b/test/asan/TestCases/Linux/read_binary_name_regtest.c
@@ -3,6 +3,7 @@
// This test uses seccomp-BPF to restrict the readlink() system call and makes
// sure ASan is still able to
// RUN: not ls /usr/include/linux/seccomp.h || ( %clang_asan %s -o %t && not %run %t 2>&1 | FileCheck %s )
+// REQUIRES: shell
// UNSUPPORTED: android
#include <errno.h>
diff --git a/test/asan/TestCases/Linux/textdomain.c b/test/asan/TestCases/Linux/textdomain.c
new file mode 100644
index 000000000000..31e5139c9f7c
--- /dev/null
+++ b/test/asan/TestCases/Linux/textdomain.c
@@ -0,0 +1,10 @@
+// RUN: %clang_asan -O0 -g %s -o %t
+// RUN: %env_asan_opts=strict_string_checks=1 %run %t
+
+#include <stdlib.h>
+#include <libintl.h>
+
+int main() {
+ textdomain(NULL);
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/strchr.c b/test/asan/TestCases/Posix/strchr.c
index df854d79ec82..7086e1374523 100644
--- a/test/asan/TestCases/Posix/strchr.c
+++ b/test/asan/TestCases/Posix/strchr.c
@@ -27,9 +27,7 @@ int main(int argc, char **argv) {
if (mprotect(p + 1, 1, PROT_NONE))
return 1;
char *r = strchr(s, 'x');
- // CHECK: AddressSanitizer: SEGV on unknown address
- // CHECK: The signal is caused by a READ memory access
- // CHECK: strchr.c:[[@LINE-3]]
+ // CHECK: AddressSanitizer: {{SEGV|BUS}} on unknown address
assert(r == p);
return 0;
diff --git a/test/asan/TestCases/Windows/dll_global_dead_strip.c b/test/asan/TestCases/Windows/dll_global_dead_strip.c
index 2664f5baff6c..15cfd5a7ddbf 100644
--- a/test/asan/TestCases/Windows/dll_global_dead_strip.c
+++ b/test/asan/TestCases/Windows/dll_global_dead_strip.c
@@ -1,8 +1,8 @@
// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
//
-// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: %clang_cl_asan /Gw -LD -O0 %s -Fe%t.dll
// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=NOSTRIP
-// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll -link -opt:ref
+// RUN: %clang_cl_asan /Gw -LD -O2 %s -Fe%t.dll -link -opt:ref
// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=STRIP
#include <stdio.h>
diff --git a/test/asan/TestCases/Windows/fuse-lld.cc b/test/asan/TestCases/Windows/fuse-lld.cc
index 7fa5d4e8a80a..c20e5ff6c786 100644
--- a/test/asan/TestCases/Windows/fuse-lld.cc
+++ b/test/asan/TestCases/Windows/fuse-lld.cc
@@ -1,6 +1,6 @@
// If we have LLD, see that things more or less work.
//
-// REQUIRES: lld
+// REQUIRES: lld-available
//
// FIXME: Use -fuse-ld=lld after the old COFF linker is removed.
// FIXME: Test will fail until we add flags for requesting dwarf or cv.
diff --git a/test/asan/TestCases/Windows/global_dead_strip.c b/test/asan/TestCases/Windows/global_dead_strip.c
index e68549050be6..2121392d9268 100644
--- a/test/asan/TestCases/Windows/global_dead_strip.c
+++ b/test/asan/TestCases/Windows/global_dead_strip.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cl_asan /O0 %s /Fe%t.exe
+// RUN: %clang_cl_asan /Gw /O0 %s /Fe%t.exe
// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=NOSTRIP
-// RUN: %clang_cl_asan /O2 %s /Fe%t.exe -link -opt:ref
+// RUN: %clang_cl_asan /Gw /O2 %s /Fe%t.exe -link -opt:ref
// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=STRIP
#include <stdio.h>
diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py
index f4ea52bec588..7e599453d1c4 100755
--- a/test/asan/android_commands/android_run.py
+++ b/test/asan/android_commands/android_run.py
@@ -18,15 +18,14 @@ def build_env():
return ' '.join(args)
is_64bit = (subprocess.check_output(['file', sys.argv[0] + '.real']).find('64-bit') != -1)
-asanwrapper = "" if is_64bit else "asanwrapper "
device_env = build_env()
device_args = ' '.join(sys.argv[1:]) # FIXME: escape?
device_stdout = device_binary + '.stdout'
device_stderr = device_binary + '.stderr'
device_exitcode = device_binary + '.exitcode'
-ret = adb(['shell', 'cd %s && %s %s%s %s >%s 2>%s ; echo $? >%s' %
- (ANDROID_TMPDIR, device_env, asanwrapper, device_binary, device_args,
+ret = adb(['shell', 'cd %s && %s %s %s >%s 2>%s ; echo $? >%s' %
+ (ANDROID_TMPDIR, device_env, device_binary, device_args,
device_stdout, device_stderr, device_exitcode)])
if ret != 0:
sys.exit(ret)
diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt
index c3123a8204eb..fb45f2f400ce 100644
--- a/test/cfi/CMakeLists.txt
+++ b/test/cfi/CMakeLists.txt
@@ -1,14 +1,48 @@
-set(CFI_LIT_TEST_MODE Standalone)
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Standalone/lit.site.cfg
- )
+set(CFI_TESTSUITES)
-set(CFI_LIT_TEST_MODE Devirt)
-configure_lit_site_cfg(
- ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
- ${CMAKE_CURRENT_BINARY_DIR}/Devirt/lit.site.cfg
- )
+macro (add_cfi_test_suites lld thinlto)
+ set(suffix)
+ if (${lld})
+ set(suffix ${suffix}-lld)
+ endif()
+ if (${thinlto})
+ set(suffix ${suffix}-thinlto)
+ endif()
+
+ set(CFI_TEST_USE_LLD ${lld})
+ set(CFI_TEST_USE_THINLTO ${thinlto})
+
+ set(CFI_LIT_TEST_MODE Standalone)
+ set(CFI_TEST_CONFIG_SUFFIX -standalone${suffix})
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Standalone${suffix}/lit.site.cfg
+ )
+ list(APPEND CFI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Standalone${suffix})
+
+ set(CFI_LIT_TEST_MODE Devirt)
+ set(CFI_TEST_CONFIG_SUFFIX -devirt${suffix})
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Devirt${suffix}/lit.site.cfg
+ )
+ list(APPEND CFI_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Devirt${suffix})
+endmacro()
+
+if (APPLE)
+ # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32741
+ add_cfi_test_suites(False False)
+elseif(WIN32)
+ # FIXME: enable ThinLTO tests after fixing http://llvm.org/pr32770
+ add_cfi_test_suites(True False)
+else()
+ add_cfi_test_suites(False False)
+ add_cfi_test_suites(False True)
+ if (COMPILER_RT_HAS_LLD)
+ add_cfi_test_suites(True False)
+ add_cfi_test_suites(True True)
+ endif()
+endif()
set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
list(APPEND CFI_TEST_DEPS
@@ -34,7 +68,7 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
LTO
)
endif()
- if(WIN32 AND COMPILER_RT_HAS_LLD)
+ if(NOT APPLE AND COMPILER_RT_HAS_LLD)
list(APPEND CFI_TEST_DEPS
lld
)
@@ -42,13 +76,11 @@ if(NOT COMPILER_RT_STANDALONE_BUILD)
endif()
add_lit_testsuite(check-cfi "Running the cfi regression tests"
- ${CMAKE_CURRENT_BINARY_DIR}/Standalone
- ${CMAKE_CURRENT_BINARY_DIR}/Devirt
+ ${CFI_TESTSUITES}
DEPENDS ${CFI_TEST_DEPS})
add_lit_target(check-cfi-and-supported "Running the cfi regression tests"
- ${CMAKE_CURRENT_BINARY_DIR}/Standalone
- ${CMAKE_CURRENT_BINARY_DIR}/Devirt
+ ${CFI_TESTSUITES}
PARAMS check_supported=1
DEPENDS ${CFI_TEST_DEPS})
diff --git a/test/cfi/create-derivers.test b/test/cfi/create-derivers.test
index a67562b1a6c8..8b569d001d89 100644
--- a/test/cfi/create-derivers.test
+++ b/test/cfi/create-derivers.test
@@ -1,20 +1,21 @@
REQUIRES: asserts
-RUN: %clangxx_cfi -c -o %t1.o %S/simple-fail.cpp
+%% Explicit -flto to override possible -flto=thin in %clangxx_cfi
+RUN: %clangxx_cfi -flto -c -o %t1.o %S/simple-fail.cpp
RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t1.o 2>&1 | FileCheck --check-prefix=B0 %s
B0: {{1B|B@@}}: {{.*}} size 1
-RUN: %clangxx_cfi -DB32 -c -o %t2.o %S/simple-fail.cpp
+RUN: %clangxx_cfi -DB32 -flto -c -o %t2.o %S/simple-fail.cpp
RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t2.o 2>&1 | FileCheck --check-prefix=B32 %s
B32: {{1B|B@@}}: {{.*}} size 24
B32-NOT: all-ones
-RUN: %clangxx_cfi -DB64 -c -o %t3.o %S/simple-fail.cpp
+RUN: %clangxx_cfi -DB64 -flto -c -o %t3.o %S/simple-fail.cpp
RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t3.o 2>&1 | FileCheck --check-prefix=B64 %s
B64: {{1B|B@@}}: {{.*}} size 54
B64-NOT: all-ones
-RUN: %clangxx_cfi -DBM -c -o %t4.o %S/simple-fail.cpp
+RUN: %clangxx_cfi -DBM -flto -c -o %t4.o %S/simple-fail.cpp
RUN: opt -lowertypetests -debug-only=lowertypetests -o /dev/null %t4.o 2>&1 | FileCheck --check-prefix=BM %s
BM: {{1B|B@@}}: {{.*}} size 84
BM-NOT: all-ones
diff --git a/test/cfi/cross-dso/dlopen.cpp b/test/cfi/cross-dso/icall/dlopen.cpp
index ee4dae2b5f7d..d238a7acec89 100644
--- a/test/cfi/cross-dso/dlopen.cpp
+++ b/test/cfi/cross-dso/icall/dlopen.cpp
@@ -55,7 +55,7 @@ struct A {
#ifdef SHARED_LIB
-#include "../utils.h"
+#include "../../utils.h"
struct B {
virtual void f();
};
diff --git a/test/cfi/cross-dso/icall/lit.local.cfg b/test/cfi/cross-dso/icall/lit.local.cfg
index db08765a2bb2..322b287a6396 100644
--- a/test/cfi/cross-dso/icall/lit.local.cfg
+++ b/test/cfi/cross-dso/icall/lit.local.cfg
@@ -1,3 +1,6 @@
# The cfi-icall checker is only supported on x86 and x86_64 for now.
if config.root.host_arch not in ['x86', 'x86_64']:
config.unsupported = True
+
+if config.root.use_thinlto:
+ config.unsupported = True
diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp
index 6566ea2fc263..fb98a50a3e78 100644
--- a/test/cfi/cross-dso/stats.cpp
+++ b/test/cfi/cross-dso/stats.cpp
@@ -3,6 +3,10 @@
// RUN: env SANITIZER_STATS_PATH=%t.stats %t
// RUN: sanstats %t.stats | FileCheck %s
+// CFI-icall is not implemented in thinlto mode => ".cfi" suffixes are missing
+// in sanstats output.
+// XFAIL: thinlto
+
struct ABase {};
struct A : ABase {
diff --git a/test/cfi/icall/lit.local.cfg b/test/cfi/icall/lit.local.cfg
index db08765a2bb2..44891c5e2de3 100644
--- a/test/cfi/icall/lit.local.cfg
+++ b/test/cfi/icall/lit.local.cfg
@@ -1,3 +1,6 @@
# The cfi-icall checker is only supported on x86 and x86_64 for now.
if config.root.host_arch not in ['x86', 'x86_64']:
config.unsupported = True
+
+if config.use_thinlto:
+ config.unsupported = True
diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg
index 3c0250632f5b..314ba5ce9e06 100644
--- a/test/cfi/lit.cfg
+++ b/test/cfi/lit.cfg
@@ -1,7 +1,7 @@
import lit.formats
import os
-config.name = 'cfi'
+config.name = 'cfi' + config.name_suffix
config.suffixes = ['.c', '.cpp', '.test']
config.test_source_root = os.path.dirname(__file__)
@@ -10,7 +10,7 @@ clangxx = ' '.join([config.clang] + config.cxx_mode_flags)
config.substitutions.append((r"%clang ", ' '.join([config.clang]) + ' '))
config.substitutions.append((r"%clangxx ", clangxx + ' '))
if config.lto_supported:
- clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=cfi '])
+ clang_cfi = ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=cfi '])
if config.cfi_lit_test_mode == "Devirt":
config.available_features.add('devirt')
diff --git a/test/cfi/lit.site.cfg.in b/test/cfi/lit.site.cfg.in
index 87e5b51e7c02..63611f659f16 100644
--- a/test/cfi/lit.site.cfg.in
+++ b/test/cfi/lit.site.cfg.in
@@ -1,6 +1,9 @@
@LIT_SITE_CFG_IN_HEADER@
+config.name_suffix = "@CFI_TEST_CONFIG_SUFFIX@"
config.cfi_lit_test_mode = "@CFI_LIT_TEST_MODE@"
+config.use_lld = @CFI_TEST_USE_LLD@
+config.use_thinlto = @CFI_TEST_USE_THINLTO@
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
index d59d7d668115..4b03a5504221 100644
--- a/test/lit.common.cfg
+++ b/test/lit.common.cfg
@@ -129,6 +129,9 @@ if sanitizer_can_use_cxxabi:
config.available_features.add('cxxabi')
if config.has_lld:
+ config.available_features.add('lld-available')
+
+if config.use_lld:
config.available_features.add('lld')
if config.can_symbolize:
@@ -180,6 +183,9 @@ def is_darwin_lto_supported():
return os.path.exists(os.path.join(config.llvm_shlib_dir, 'libLTO.dylib'))
def is_linux_lto_supported():
+ if config.use_lld:
+ return True
+
if not os.path.exists(os.path.join(config.llvm_shlib_dir, 'LLVMgold.so')):
return False
@@ -202,7 +208,10 @@ if config.host_os == 'Darwin' and is_darwin_lto_supported():
elif config.host_os == 'Linux' and is_linux_lto_supported():
config.lto_supported = True
config.lto_launch = []
- config.lto_flags = ["-fuse-ld=gold"]
+ if config.use_lld:
+ config.lto_flags = ["-fuse-ld=lld"]
+ else:
+ config.lto_flags = ["-fuse-ld=gold"]
elif config.host_os == 'Windows' and is_windows_lto_supported():
config.lto_supported = True
config.lto_launch = []
@@ -213,6 +222,11 @@ else:
if config.lto_supported:
config.available_features.add('lto')
+ if config.use_thinlto:
+ config.available_features.add('thinlto')
+ config.lto_flags += ["-flto=thin"]
+ else:
+ config.lto_flags += ["-flto"]
# Ask llvm-config about assertion mode.
try:
diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in
index 387f4d4a743b..0ad03a180042 100644
--- a/test/lit.common.configured.in
+++ b/test/lit.common.configured.in
@@ -28,6 +28,8 @@ set_default("emulator", "@COMPILER_RT_EMULATOR@")
set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@)
set_default("has_lld", @COMPILER_RT_HAS_LLD_PYBOOL@)
set_default("can_symbolize", @CAN_SYMBOLIZE@)
+set_default("use_lld", False)
+set_default("use_thinlto", False)
config.available_features.add('target-is-%s' % config.target_arch)
# LLVM tools dir can be passed in lit parameters, so try to
diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg
index 7020bd8473e5..da439d4c0282 100644
--- a/test/lsan/lit.common.cfg
+++ b/test/lsan/lit.common.cfg
@@ -67,8 +67,9 @@ config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) )
config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) )
config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) )
-# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only.
-if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', 'armv7l']:
+# LeakSanitizer tests are currently supported on x86-64 Linux, PowerPC64 Linux, arm Linux, and mips64 Linux only.
+supported_linux = config.host_os is 'Linux' and config.host_arch in ['x86_64', 'ppc64', 'mips64', 'arm', 'armhf', 'armv7l']
+if not (supported_linux):
config.unsupported = True
# Don't support Thumb due to broken fast unwinder
diff --git a/test/safestack/lit.cfg b/test/safestack/lit.cfg
index d4ec73ce703b..fb5672936f28 100644
--- a/test/safestack/lit.cfg
+++ b/test/safestack/lit.cfg
@@ -16,7 +16,7 @@ config.substitutions.append( ("%clang_nosafestack ", config.clang + " -O0 -fno-s
config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsanitize=safe-stack ") )
if config.lto_supported:
- config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=safe-stack '])))
+ config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-fsanitize=safe-stack '])))
# SafeStack tests are currently supported on Linux, FreeBSD and Darwin only.
if config.host_os not in ['Linux', 'FreeBSD', 'Darwin']:
diff --git a/test/tsan/Darwin/deadlock.mm b/test/tsan/Darwin/deadlock.mm
new file mode 100644
index 000000000000..36ddfad54f7c
--- /dev/null
+++ b/test/tsan/Darwin/deadlock.mm
@@ -0,0 +1,47 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+pthread_mutex_t m1;
+pthread_mutex_t m2;
+
+int main(int argc, const char *argv[]) {
+ barrier_init(&barrier, 2);
+ fprintf(stderr, "Hello world.\n");
+
+ pthread_mutex_init(&m1, NULL);
+ pthread_mutex_init(&m2, NULL);
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ pthread_mutex_lock(&m1);
+ pthread_mutex_lock(&m2);
+ pthread_mutex_unlock(&m2);
+ pthread_mutex_unlock(&m1);
+
+ barrier_wait(&barrier);
+ });
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ barrier_wait(&barrier);
+
+ pthread_mutex_lock(&m2);
+ pthread_mutex_lock(&m1);
+ pthread_mutex_unlock(&m1);
+ pthread_mutex_unlock(&m2);
+
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+ });
+
+ CFRunLoopRun();
+
+ fprintf(stderr, "Done.\n");
+ return 0;
+}
+
+// CHECK: Hello world.
+// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
+// CHECK: Done.
diff --git a/test/tsan/Darwin/debug_external.cc b/test/tsan/Darwin/debug_external.cc
index 217690fc5dd0..2418a271b23c 100644
--- a/test/tsan/Darwin/debug_external.cc
+++ b/test/tsan/Darwin/debug_external.cc
@@ -17,8 +17,6 @@ int __tsan_get_report_loc(void *report, unsigned long idx, const char **type,
unsigned long trace_size);
int __tsan_get_report_loc_object_type(void *report, unsigned long idx,
const char **object_type);
-void *__tsan_external_register_tag(const char *object_type);
-void __tsan_external_assign_tag(void *addr, void *tag);
}
void *Thread(void *arg) {
diff --git a/test/tsan/Darwin/external-dups.cc b/test/tsan/Darwin/external-dups.cc
new file mode 100644
index 000000000000..79432bac4a02
--- /dev/null
+++ b/test/tsan/Darwin/external-dups.cc
@@ -0,0 +1,58 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#include <thread>
+
+#import "../test.h"
+
+void *tag;
+
+__attribute__((no_sanitize("thread")))
+void ExternalWrite(void *addr) {
+ __tsan_external_write(addr, __builtin_return_address(0), tag);
+}
+
+int main(int argc, char *argv[]) {
+ barrier_init(&barrier, 2);
+ tag = __tsan_external_register_tag("HelloWorld");
+ fprintf(stderr, "Start.\n");
+ // CHECK: Start.
+
+ for (int i = 0; i < 4; i++) {
+ void *opaque_object = malloc(16);
+ std::thread t1([opaque_object] {
+ ExternalWrite(opaque_object);
+ barrier_wait(&barrier);
+ });
+ std::thread t2([opaque_object] {
+ barrier_wait(&barrier);
+ ExternalWrite(opaque_object);
+ });
+ // CHECK: WARNING: ThreadSanitizer: race on a library object
+ t1.join();
+ t2.join();
+ }
+
+ fprintf(stderr, "First phase done.\n");
+ // CHECK: First phase done.
+
+ for (int i = 0; i < 4; i++) {
+ void *opaque_object = malloc(16);
+ std::thread t1([opaque_object] {
+ ExternalWrite(opaque_object);
+ barrier_wait(&barrier);
+ });
+ std::thread t2([opaque_object] {
+ barrier_wait(&barrier);
+ ExternalWrite(opaque_object);
+ });
+ // CHECK: WARNING: ThreadSanitizer: race on a library object
+ t1.join();
+ t2.join();
+ }
+
+ fprintf(stderr, "Second phase done.\n");
+ // CHECK: Second phase done.
+}
+
+// CHECK: ThreadSanitizer: reported 2 warnings
diff --git a/test/tsan/Darwin/external-ignore-noninstrumented.cc b/test/tsan/Darwin/external-ignore-noninstrumented.cc
new file mode 100644
index 000000000000..d2acaf54b263
--- /dev/null
+++ b/test/tsan/Darwin/external-ignore-noninstrumented.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -shared %p/external-lib.cc -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \
+// RUN: -o %t-lib.dylib -install_name @rpath/`basename %t-lib.dylib`
+
+// RUN: %clangxx_tsan -shared %p/external-noninstrumented-module.cc %t-lib.dylib -fno-sanitize=thread \
+// RUN: -o %t-module.dylib -install_name @rpath/`basename %t-module.dylib`
+
+// RUN: %clangxx_tsan %s %t-module.dylib -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+extern "C" void NonInstrumentedModule();
+int main(int argc, char *argv[]) {
+ NonInstrumentedModule();
+ fprintf(stderr, "Done.\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/external-lib.cc b/test/tsan/Darwin/external-lib.cc
new file mode 100644
index 000000000000..f0afdf1dc060
--- /dev/null
+++ b/test/tsan/Darwin/external-lib.cc
@@ -0,0 +1,68 @@
+// This file is used from other tests.
+// RUN: true
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct MyObject;
+typedef MyObject *MyObjectRef;
+extern "C" {
+ void InitializeLibrary();
+ MyObject *ObjectCreate();
+ long ObjectRead(MyObject *);
+ void ObjectWrite(MyObject *, long);
+ void ObjectWriteAnother(MyObject *, long);
+}
+
+struct MyObject {
+ long _val;
+ long _another;
+};
+
+#if defined(USE_TSAN_CALLBACKS)
+static void *tag;
+void *(*callback_register_tag)(const char *object_type);
+void *(*callback_assign_tag)(void *addr, void *tag);
+void (*callback_read)(void *addr, void *caller_pc, void *tag);
+void (*callback_write)(void *addr, void *caller_pc, void *tag);
+#endif
+
+void InitializeLibrary() {
+#if defined(USE_TSAN_CALLBACKS)
+ callback_register_tag = (decltype(callback_register_tag))dlsym(RTLD_DEFAULT, "__tsan_external_register_tag");
+ callback_assign_tag = (decltype(callback_assign_tag))dlsym(RTLD_DEFAULT, "__tsan_external_assign_tag");
+ callback_read = (decltype(callback_read))dlsym(RTLD_DEFAULT, "__tsan_external_read");
+ callback_write = (decltype(callback_write))dlsym(RTLD_DEFAULT, "__tsan_external_write");
+ tag = callback_register_tag("MyLibrary::MyObject");
+#endif
+}
+
+MyObject *ObjectCreate() {
+ MyObject *ref = (MyObject *)malloc(sizeof(MyObject));
+#if defined(USE_TSAN_CALLBACKS)
+ callback_assign_tag(ref, tag);
+#endif
+ return ref;
+}
+
+long ObjectRead(MyObject *ref) {
+#if defined(USE_TSAN_CALLBACKS)
+ callback_read(ref, __builtin_return_address(0), tag);
+#endif
+ return ref->_val;
+}
+
+void ObjectWrite(MyObject *ref, long val) {
+#if defined(USE_TSAN_CALLBACKS)
+ callback_write(ref, __builtin_return_address(0), tag);
+#endif
+ ref->_val = val;
+}
+
+void ObjectWriteAnother(MyObject *ref, long val) {
+#if defined(USE_TSAN_CALLBACKS)
+ callback_write(ref, __builtin_return_address(0), tag);
+#endif
+ ref->_another = val;
+}
diff --git a/test/tsan/Darwin/external-noninstrumented-module.cc b/test/tsan/Darwin/external-noninstrumented-module.cc
new file mode 100644
index 000000000000..ce65970834e5
--- /dev/null
+++ b/test/tsan/Darwin/external-noninstrumented-module.cc
@@ -0,0 +1,27 @@
+// This file is used from other tests.
+// RUN: true
+
+#include <thread>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct MyObject;
+typedef MyObject *MyObjectRef;
+extern "C" {
+ void InitializeLibrary();
+ MyObject *ObjectCreate();
+ long ObjectRead(MyObject *);
+ void ObjectWrite(MyObject *, long);
+ void ObjectWriteAnother(MyObject *, long);
+}
+
+extern "C" void NonInstrumentedModule() {
+ InitializeLibrary();
+
+ MyObjectRef ref = ObjectCreate();
+ std::thread t1([ref]{ ObjectWrite(ref, 42); });
+ std::thread t2([ref]{ ObjectWrite(ref, 43); });
+ t1.join();
+ t2.join();
+}
diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc
index 2605480d7b82..211694ab7db1 100644
--- a/test/tsan/Darwin/external.cc
+++ b/test/tsan/Darwin/external.cc
@@ -1,12 +1,12 @@
-// RUN: %clangxx_tsan %s -shared -DSHARED_LIB \
+// RUN: %clangxx_tsan %p/external-lib.cc -shared \
// RUN: -o %t-lib-instrumented.dylib \
// RUN: -install_name @rpath/`basename %t-lib-instrumented.dylib`
-// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread \
+// RUN: %clangxx_tsan %p/external-lib.cc -shared -fno-sanitize=thread \
// RUN: -o %t-lib-noninstrumented.dylib \
// RUN: -install_name @rpath/`basename %t-lib-noninstrumented.dylib`
-// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \
+// RUN: %clangxx_tsan %p/external-lib.cc -shared -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \
// RUN: -o %t-lib-noninstrumented-callbacks.dylib \
// RUN: -install_name @rpath/`basename %t-lib-noninstrumented-callbacks.dylib`
@@ -23,8 +23,6 @@
#include <thread>
-#include <dlfcn.h>
-#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,62 +36,6 @@ extern "C" {
void ObjectWriteAnother(MyObject *, long);
}
-#if defined(SHARED_LIB)
-
-struct MyObject {
- long _val;
- long _another;
-};
-
-#if defined(USE_TSAN_CALLBACKS)
-static void *tag;
-void *(*callback_register_tag)(const char *object_type);
-void *(*callback_assign_tag)(void *addr, void *tag);
-void (*callback_read)(void *addr, void *caller_pc, void *tag);
-void (*callback_write)(void *addr, void *caller_pc, void *tag);
-#endif
-
-void InitializeLibrary() {
-#if defined(USE_TSAN_CALLBACKS)
- callback_register_tag = (decltype(callback_register_tag))dlsym(RTLD_DEFAULT, "__tsan_external_register_tag");
- callback_assign_tag = (decltype(callback_assign_tag))dlsym(RTLD_DEFAULT, "__tsan_external_assign_tag");
- callback_read = (decltype(callback_read))dlsym(RTLD_DEFAULT, "__tsan_external_read");
- callback_write = (decltype(callback_write))dlsym(RTLD_DEFAULT, "__tsan_external_write");
- tag = callback_register_tag("MyLibrary::MyObject");
-#endif
-}
-
-MyObject *ObjectCreate() {
- MyObject *ref = (MyObject *)malloc(sizeof(MyObject));
-#if defined(USE_TSAN_CALLBACKS)
- callback_assign_tag(ref, tag);
-#endif
- return ref;
-}
-
-long ObjectRead(MyObject *ref) {
-#if defined(USE_TSAN_CALLBACKS)
- callback_read(ref, __builtin_return_address(0), tag);
-#endif
- return ref->_val;
-}
-
-void ObjectWrite(MyObject *ref, long val) {
-#if defined(USE_TSAN_CALLBACKS)
- callback_write(ref, __builtin_return_address(0), tag);
-#endif
- ref->_val = val;
-}
-
-void ObjectWriteAnother(MyObject *ref, long val) {
-#if defined(USE_TSAN_CALLBACKS)
- callback_write(ref, __builtin_return_address(0), tag);
-#endif
- ref->_another = val;
-}
-
-#else // defined(SHARED_LIB)
-
int main(int argc, char *argv[]) {
InitializeLibrary();
@@ -126,11 +68,11 @@ int main(int argc, char *argv[]) {
// TEST2-NOT: WARNING: ThreadSanitizer
// TEST3: WARNING: ThreadSanitizer: race on a library object
- // TEST3: {{Mutating|read-only}} access of object MyLibrary::MyObject at
+ // TEST3: {{Mutating|read-only}} access of MyLibrary::MyObject at
// TEST3: {{ObjectWrite|ObjectRead}}
- // TEST3: Previous {{mutating|read-only}} access of object MyLibrary::MyObject at
+ // TEST3: Previous {{mutating|read-only}} access of MyLibrary::MyObject at
// TEST3: {{ObjectWrite|ObjectRead}}
- // TEST3: Location is MyLibrary::MyObject object of size 16 at
+ // TEST3: Location is MyLibrary::MyObject of size 16 at
// TEST3: {{ObjectCreate}}
fprintf(stderr, "RW test done\n");
@@ -149,15 +91,13 @@ int main(int argc, char *argv[]) {
// TEST2-NOT: WARNING: ThreadSanitizer
// TEST3: WARNING: ThreadSanitizer: race on a library object
- // TEST3: Mutating access of object MyLibrary::MyObject at
+ // TEST3: Mutating access of MyLibrary::MyObject at
// TEST3: {{ObjectWrite|ObjectWriteAnother}}
- // TEST3: Previous mutating access of object MyLibrary::MyObject at
+ // TEST3: Previous mutating access of MyLibrary::MyObject at
// TEST3: {{ObjectWrite|ObjectWriteAnother}}
- // TEST3: Location is MyLibrary::MyObject object of size 16 at
+ // TEST3: Location is MyLibrary::MyObject of size 16 at
// TEST3: {{ObjectCreate}}
fprintf(stderr, "WW test done\n");
// CHECK: WW test done
}
-
-#endif // defined(SHARED_LIB)
diff --git a/test/tsan/test.h b/test/tsan/test.h
index 6b981c09f53d..bc4f7aad55fe 100644
--- a/test/tsan/test.h
+++ b/test/tsan/test.h
@@ -8,6 +8,8 @@
#include <stdarg.h>
#include "sanitizer_common/print_address.h"
+#include <sanitizer/tsan_interface.h>
+
#ifdef __APPLE__
#include <mach/mach_time.h>
#endif
diff --git a/test/tsan/unaligned_race.cc b/test/tsan/unaligned_race.cc
index 030642a4ddfb..5850b21542d4 100644
--- a/test/tsan/unaligned_race.cc
+++ b/test/tsan/unaligned_race.cc
@@ -6,31 +6,22 @@
volatile uint64_t objs[8*2*(2 + 4 + 8)][2];
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(volatile void *addr);
-uint32_t __sanitizer_unaligned_load32(volatile void *addr);
-uint64_t __sanitizer_unaligned_load64(volatile void *addr);
-void __sanitizer_unaligned_store16(volatile void *addr, uint16_t v);
-void __sanitizer_unaligned_store32(volatile void *addr, uint32_t v);
-void __sanitizer_unaligned_store64(volatile void *addr, uint64_t v);
-}
-
// All this mess is to generate unique stack for each race,
// otherwise tsan will suppress similar stacks.
-static NOINLINE void access(volatile char *p, int sz, int rw) {
+static NOINLINE void access(volatile void *p, int sz, int rw) {
if (rw) {
switch (sz) {
- case 0: __sanitizer_unaligned_store16(p, 0); break;
- case 1: __sanitizer_unaligned_store32(p, 0); break;
- case 2: __sanitizer_unaligned_store64(p, 0); break;
+ case 0: __sanitizer_unaligned_store16((void *)p, 0); break;
+ case 1: __sanitizer_unaligned_store32((void *)p, 0); break;
+ case 2: __sanitizer_unaligned_store64((void *)p, 0); break;
default: exit(1);
}
} else {
switch (sz) {
- case 0: __sanitizer_unaligned_load16(p); break;
- case 1: __sanitizer_unaligned_load32(p); break;
- case 2: __sanitizer_unaligned_load64(p); break;
+ case 0: __sanitizer_unaligned_load16((void *)p); break;
+ case 1: __sanitizer_unaligned_load32((void *)p); break;
+ case 2: __sanitizer_unaligned_load64((void *)p); break;
default: exit(1);
}
}