Hi! When I've tried to compile the attached testcase (I was trying to see if tsan could discover the emutls.c data race), I got ICEs because expr_ptr in certain cases wasn't is_gimple_val and thus was invalid to pass it directly to a call as argument, fixed thusly.
Unfortunately, trying to compile it dynamically against libtsan.so doesn't work (apparently it is using -fvisibility=hidden, but not saying the public entry points have default visibility), compiling it by hand statically against libtsan.a (we don't have -static-libtsan yet) failed at runtime, complaining the binary isn't a PIE - can't it really support normal executables?, and when compiled/linked as PIE, I got ================== WARNING: ThreadSanitizer: thread leak (pid=31150) Thread 3 (tid=31153, finished) created at: #0 pthread_create ??:0 (exe+0x00000000e4dc) #1 main ??:0 (exe+0x00000000505f) ================== ================== WARNING: ThreadSanitizer: thread leak (pid=31150) Thread 4 (tid=31155, finished) created at: #0 pthread_create ??:0 (exe+0x00000000e4dc) #1 main ??:0 (exe+0x00000000505f) ================== ================== WARNING: ThreadSanitizer: thread leak (pid=31150) Thread 5 (tid=31156, finished) created at: #0 pthread_create ??:0 (exe+0x00000000e4dc) #1 main ??:0 (exe+0x00000000505f) ================== ThreadSanitizer: reported 3 warnings which is probably not what I was expecting to see. 2012-12-01 Jakub Jelinek <ja...@redhat.com> * tsan.c (instrument_expr): If expr_ptr isn't a gimple val, first store it into a SSA_NAME. --- gcc/tsan.c.jj 2012-11-30 19:17:13.000000000 +0100 +++ gcc/tsan.c 2012-11-30 21:50:54.695392123 +0100 @@ -93,10 +93,11 @@ is_vptr_store (gimple stmt, tree expr, b static bool instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write) { - tree base, rhs, expr_type, expr_ptr, builtin_decl; + tree base, rhs, expr_ptr, builtin_decl; basic_block bb; HOST_WIDE_INT size; gimple stmt, g; + gimple_seq seq; location_t loc; size = int_size_in_bytes (TREE_TYPE (expr)); @@ -139,21 +140,25 @@ instrument_expr (gimple_stmt_iterator gs rhs = is_vptr_store (stmt, expr, is_write); gcc_checking_assert (rhs != NULL || is_gimple_addressable (expr)); expr_ptr = build_fold_addr_expr (unshare_expr (expr)); - if (rhs == NULL) + seq = NULL; + if (!is_gimple_val (expr_ptr)) { - expr_type = TREE_TYPE (expr); - while (TREE_CODE (expr_type) == ARRAY_TYPE) - expr_type = TREE_TYPE (expr_type); - size = int_size_in_bytes (expr_type); - g = gimple_build_call (get_memory_access_decl (is_write, size), - 1, expr_ptr); + g = gimple_build_assign (make_ssa_name (TREE_TYPE (expr_ptr), NULL), + expr_ptr); + expr_ptr = gimple_assign_lhs (g); + gimple_set_location (g, loc); + gimple_seq_add_stmt_without_update (&seq, g); } + if (rhs == NULL) + g = gimple_build_call (get_memory_access_decl (is_write, size), + 1, expr_ptr); else { builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE); g = gimple_build_call (builtin_decl, 1, expr_ptr); } gimple_set_location (g, loc); + gimple_seq_add_stmt_without_update (&seq, g); /* Instrumentation for assignment of a function result must be inserted after the call. Instrumentation for reads of function arguments must be inserted before the call. @@ -170,13 +175,13 @@ instrument_expr (gimple_stmt_iterator gs bb = gsi_bb (gsi); e = find_fallthru_edge (bb->succs); if (e) - gsi_insert_seq_on_edge_immediate (e, g); + gsi_insert_seq_on_edge_immediate (e, seq); } else - gsi_insert_after (&gsi, g, GSI_NEW_STMT); + gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT); } else - gsi_insert_before (&gsi, g, GSI_SAME_STMT); + gsi_insert_before (&gsi, seq, GSI_SAME_STMT); return true; } Jakub
#include <pthread.h> #include <stdlib.h> #include <string.h> #include <stdint.h> pthread_key_t key; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; struct S { uintptr_t offset; size_t size; }; struct T { uintptr_t size; void **data[]; }; void destroy (void *x) { struct T *p = x; uintptr_t size = p->size; uintptr_t i; for (i = 0; i < size; ++i) free (p->data[i]); free (x); } void init (void) { if (pthread_key_create (&key, destroy)) exit (0); } static uintptr_t size; void * foo (struct S *x) { uintptr_t offset = x->offset; if (__builtin_expect (offset == 0, 0)) { static pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once (&once, init); pthread_mutex_lock (&lock); offset = x->offset; if (offset == 0) { offset = ++size; x->offset = offset; } pthread_mutex_unlock (&lock); } struct T *p = (struct T *) pthread_getspecific (key); if (__builtin_expect (p == NULL, 0)) { uintptr_t s = offset + 2; p = (struct T *) calloc (s + 1, sizeof (void *)); if (p == NULL) exit (0); p->size = s; pthread_setspecific (key, (void *) p); } else if (__builtin_expect (offset > p->size, 0)) { uintptr_t o = p->size; uintptr_t s = 2 * o; if (offset > s) s = offset + 2; p = realloc (p, (s + 1) * sizeof (void *)); if (p == NULL) exit (0); memset (p->data + o, 0, (s - o) * sizeof (void *)); p->size = s; pthread_setspecific (key, (void *) p); } void *ret = p->data[offset - 1]; if (__builtin_expect (ret == NULL, 0)) { ret = malloc (x->size); if (ret == NULL) exit (0); p->data[offset - 1] = ret; } return ret; } struct S s[3] = { { 0, 5 }, { 0, 12 }, { 0, 21 } }; void * tf (void *arg) { (void) arg; foo (&s[0]); foo (&s[1]); foo (&s[0]); foo (&s[2]); return NULL; } int main (void) { pthread_t p[2]; int i; for (i = 0; i < 5; i++) if (pthread_create (&p[i], NULL, tf, NULL)) return 0; for (i = 0; i < 5; i++) pthread_join (p[i], NULL); return 0; }