Workaround Thread Sanitizer (TSan) false positive warnings
authorIvan Maidanski <ivmai@mail.ru>
Thu, 21 Sep 2017 08:36:30 +0000 (11:36 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Fri, 13 Oct 2017 07:10:54 +0000 (10:10 +0300)
* src/atomic_ops.h [__has_feature && __has_feature(thread_sanitizer)]
(AO_THREAD_SANITIZER): New internal macro.
* src/atomic_ops.h [!AO_ATTR_NO_SANITIZE_THREAD]
(AO_ATTR_NO_SANITIZE_THREAD): Likewise.
* src/atomic_ops/generalize-arithm.h: Regenerate.
* src/atomic_ops/generalize-small.h: Likewise.
* src/atomic_ops/generalize-arithm.template
(AO_XSIZE_fetch_and_add_full, AO_XSIZE_fetch_and_add_acquire,
AO_XSIZE_fetch_and_add_release, AO_XSIZE_fetch_and_add,
AO_XSIZE_and_full, AO_XSIZE_or_full, AO_XSIZE_xor_full): Add
AO_ATTR_NO_SANITIZE_THREAD attribute.
* src/atomic_ops/generalize-small.template (AO_XSIZE_load_read,
AO_XSIZE_load_full, AO_XSIZE_load_acquire, AO_XSIZE_load,
AO_XSIZE_store_write, AO_XSIZE_store, AO_XSIZE_store_release,
AO_XSIZE_store_full: Likewise.
* src/atomic_ops_stack.c [AO_USE_ALMOST_LOCK_FREE]
(AO_stack_push_explicit_aux_release): Likewise.
* src/atomic_ops_stack.c [AO_HAVE_compare_double_and_swap_double]
(AO_stack_push_release, AO_stack_pop_acquire): Likewise.
* tests/test_malloc.c (cons): Likewise.
* src/atomic_ops/sysdeps/gcc/x86.h [AO_GCC_ATOMIC_TEST_AND_SET
&& __clang__ && __x86_64__ && !__ILP32__ && AO_THREAD_SANITIZER]
(AO_SKIPATOMIC_double_compare_and_swap_ANY, AO_SKIPATOMIC_double_load,
AO_SKIPATOMIC_double_load_acquire, AO_SKIPATOMIC_double_store,
AO_SKIPATOMIC_double_store_release): Define; update comment.
* src/atomic_ops_malloc.c [AO_THREAD_SANITIZER] (AO_malloc, AO_free):
Use AO_store/load to write/read log_sz value in object header.
* tests/test_atomic.c (do_junk): New function (declared with
AO_ATTR_NO_SANITIZE_THREAD attribute); multiply junk value by two
different constant values.
* tests/test_atomic.c (test_and_set_thr): Call do_junk() instead of
operating on junk global variable directly.

src/atomic_ops.h
src/atomic_ops/generalize-arithm.h
src/atomic_ops/generalize-arithm.template
src/atomic_ops/generalize-small.h
src/atomic_ops/generalize-small.template
src/atomic_ops/sysdeps/gcc/x86.h
src/atomic_ops_malloc.c
src/atomic_ops_stack.c
tests/test_atomic.c
tests/test_malloc.c

index 03f82a6..568a8c5 100644 (file)
 # if __has_feature(memory_sanitizer)
 #   define AO_MEMORY_SANITIZER
 # endif
+# if __has_feature(thread_sanitizer)
+#   define AO_THREAD_SANITIZER
+# endif
 #endif
 
 #ifndef AO_ATTR_NO_SANITIZE_MEMORY
 # endif
 #endif /* !AO_ATTR_NO_SANITIZE_MEMORY */
 
+#ifndef AO_ATTR_NO_SANITIZE_THREAD
+# if defined(AO_THREAD_SANITIZER) \
+        && (!defined(__clang__) || AO_CLANG_PREREQ(3, 8))
+#   define AO_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
+# else
+#   define AO_ATTR_NO_SANITIZE_THREAD /* empty */
+# endif
+#endif /* !AO_ATTR_NO_SANITIZE_THREAD */
+
 #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
 # define AO_compiler_barrier() __asm__ __volatile__("" : : : "memory")
 #elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
index e925b10..27ccf9b 100644 (file)
     && !defined(AO_HAVE_char_fetch_and_add_full)
   AO_INLINE unsigned/**/char
   AO_char_fetch_and_add_full(volatile unsigned/**/char *addr, unsigned/**/char incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_fetch_and_add_acquire)
   AO_INLINE unsigned/**/char
   AO_char_fetch_and_add_acquire(volatile unsigned/**/char *addr, unsigned/**/char incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_fetch_and_add_release)
   AO_INLINE unsigned/**/char
   AO_char_fetch_and_add_release(volatile unsigned/**/char *addr, unsigned/**/char incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_fetch_and_add)
   AO_INLINE unsigned/**/char
   AO_char_fetch_and_add(volatile unsigned/**/char *addr, unsigned/**/char incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_and_full)
   AO_INLINE void
   AO_char_and_full(volatile unsigned/**/char *addr, unsigned/**/char value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_or_full)
   AO_INLINE void
   AO_char_or_full(volatile unsigned/**/char *addr, unsigned/**/char value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_char_xor_full)
   AO_INLINE void
   AO_char_xor_full(volatile unsigned/**/char *addr, unsigned/**/char value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old;
 
     && !defined(AO_HAVE_short_fetch_and_add_full)
   AO_INLINE unsigned/**/short
   AO_short_fetch_and_add_full(volatile unsigned/**/short *addr, unsigned/**/short incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_fetch_and_add_acquire)
   AO_INLINE unsigned/**/short
   AO_short_fetch_and_add_acquire(volatile unsigned/**/short *addr, unsigned/**/short incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_fetch_and_add_release)
   AO_INLINE unsigned/**/short
   AO_short_fetch_and_add_release(volatile unsigned/**/short *addr, unsigned/**/short incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_fetch_and_add)
   AO_INLINE unsigned/**/short
   AO_short_fetch_and_add(volatile unsigned/**/short *addr, unsigned/**/short incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_and_full)
   AO_INLINE void
   AO_short_and_full(volatile unsigned/**/short *addr, unsigned/**/short value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_or_full)
   AO_INLINE void
   AO_short_or_full(volatile unsigned/**/short *addr, unsigned/**/short value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_short_xor_full)
   AO_INLINE void
   AO_short_xor_full(volatile unsigned/**/short *addr, unsigned/**/short value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old;
 
     && !defined(AO_HAVE_int_fetch_and_add_full)
   AO_INLINE unsigned
   AO_int_fetch_and_add_full(volatile unsigned *addr, unsigned incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_fetch_and_add_acquire)
   AO_INLINE unsigned
   AO_int_fetch_and_add_acquire(volatile unsigned *addr, unsigned incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_fetch_and_add_release)
   AO_INLINE unsigned
   AO_int_fetch_and_add_release(volatile unsigned *addr, unsigned incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_fetch_and_add)
   AO_INLINE unsigned
   AO_int_fetch_and_add(volatile unsigned *addr, unsigned incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_and_full)
   AO_INLINE void
   AO_int_and_full(volatile unsigned *addr, unsigned value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_or_full)
   AO_INLINE void
   AO_int_or_full(volatile unsigned *addr, unsigned value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_int_xor_full)
   AO_INLINE void
   AO_int_xor_full(volatile unsigned *addr, unsigned value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old;
 
     && !defined(AO_HAVE_fetch_and_add_full)
   AO_INLINE AO_t
   AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_fetch_and_add_acquire)
   AO_INLINE AO_t
   AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_fetch_and_add_release)
   AO_INLINE AO_t
   AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_fetch_and_add)
   AO_INLINE AO_t
   AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_and_full)
   AO_INLINE void
   AO_and_full(volatile AO_t *addr, AO_t value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_or_full)
   AO_INLINE void
   AO_or_full(volatile AO_t *addr, AO_t value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
     && !defined(AO_HAVE_xor_full)
   AO_INLINE void
   AO_xor_full(volatile AO_t *addr, AO_t value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old;
 
index 24161a4..69735fd 100644 (file)
     && !defined(AO_HAVE_XSIZE_fetch_and_add_full)
   AO_INLINE XCTYPE
   AO_XSIZE_fetch_and_add_full(volatile XCTYPE *addr, XCTYPE incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_fetch_and_add_acquire)
   AO_INLINE XCTYPE
   AO_XSIZE_fetch_and_add_acquire(volatile XCTYPE *addr, XCTYPE incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_fetch_and_add_release)
   AO_INLINE XCTYPE
   AO_XSIZE_fetch_and_add_release(volatile XCTYPE *addr, XCTYPE incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_fetch_and_add)
   AO_INLINE XCTYPE
   AO_XSIZE_fetch_and_add(volatile XCTYPE *addr, XCTYPE incr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_and_full)
   AO_INLINE void
   AO_XSIZE_and_full(volatile XCTYPE *addr, XCTYPE value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_or_full)
   AO_INLINE void
   AO_XSIZE_or_full(volatile XCTYPE *addr, XCTYPE value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
     && !defined(AO_HAVE_XSIZE_xor_full)
   AO_INLINE void
   AO_XSIZE_xor_full(volatile XCTYPE *addr, XCTYPE value)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old;
 
index 94538af..8e26abf 100644 (file)
     && !defined(AO_HAVE_char_load_read)
 # define AO_char_CAS_BASED_LOAD_READ
   AO_INLINE unsigned/**/char
-  AO_char_load_read(const volatile unsigned/**/char *addr)
+  AO_char_load_read(const volatile unsigned/**/char *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char result;
 
 #if defined(AO_HAVE_char_compare_and_swap_full) \
     && !defined(AO_HAVE_char_load_full)
   AO_INLINE unsigned/**/char
-  AO_char_load_full(const volatile unsigned/**/char *addr)
+  AO_char_load_full(const volatile unsigned/**/char *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char result;
 
     && !defined(AO_HAVE_char_load_acquire)
   AO_INLINE unsigned/**/char
   AO_char_load_acquire(const volatile unsigned/**/char *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char result;
 
 
 #if defined(AO_HAVE_char_compare_and_swap) && !defined(AO_HAVE_char_load)
   AO_INLINE unsigned/**/char
-  AO_char_load(const volatile unsigned/**/char *addr)
+  AO_char_load(const volatile unsigned/**/char *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char result;
 
     && !defined(AO_HAVE_char_store_write)
   AO_INLINE void
   AO_char_store_write(volatile unsigned/**/char *addr, unsigned/**/char new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old_val;
 
 #if defined(AO_HAVE_char_compare_and_swap) && !defined(AO_HAVE_char_store)
   AO_INLINE void
   AO_char_store(volatile unsigned/**/char *addr, unsigned/**/char new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old_val;
 
     && !defined(AO_HAVE_char_store_release)
   AO_INLINE void
   AO_char_store_release(volatile unsigned/**/char *addr, unsigned/**/char new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old_val;
 
     && !defined(AO_HAVE_char_store_full)
   AO_INLINE void
   AO_char_store_full(volatile unsigned/**/char *addr, unsigned/**/char new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/char old_val;
 
     && !defined(AO_HAVE_short_load_read)
 # define AO_short_CAS_BASED_LOAD_READ
   AO_INLINE unsigned/**/short
-  AO_short_load_read(const volatile unsigned/**/short *addr)
+  AO_short_load_read(const volatile unsigned/**/short *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short result;
 
 #if defined(AO_HAVE_short_compare_and_swap_full) \
     && !defined(AO_HAVE_short_load_full)
   AO_INLINE unsigned/**/short
-  AO_short_load_full(const volatile unsigned/**/short *addr)
+  AO_short_load_full(const volatile unsigned/**/short *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short result;
 
     && !defined(AO_HAVE_short_load_acquire)
   AO_INLINE unsigned/**/short
   AO_short_load_acquire(const volatile unsigned/**/short *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short result;
 
 
 #if defined(AO_HAVE_short_compare_and_swap) && !defined(AO_HAVE_short_load)
   AO_INLINE unsigned/**/short
-  AO_short_load(const volatile unsigned/**/short *addr)
+  AO_short_load(const volatile unsigned/**/short *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short result;
 
     && !defined(AO_HAVE_short_store_write)
   AO_INLINE void
   AO_short_store_write(volatile unsigned/**/short *addr, unsigned/**/short new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old_val;
 
 #if defined(AO_HAVE_short_compare_and_swap) && !defined(AO_HAVE_short_store)
   AO_INLINE void
   AO_short_store(volatile unsigned/**/short *addr, unsigned/**/short new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old_val;
 
     && !defined(AO_HAVE_short_store_release)
   AO_INLINE void
   AO_short_store_release(volatile unsigned/**/short *addr, unsigned/**/short new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old_val;
 
     && !defined(AO_HAVE_short_store_full)
   AO_INLINE void
   AO_short_store_full(volatile unsigned/**/short *addr, unsigned/**/short new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned/**/short old_val;
 
     && !defined(AO_HAVE_int_load_read)
 # define AO_int_CAS_BASED_LOAD_READ
   AO_INLINE unsigned
-  AO_int_load_read(const volatile unsigned *addr)
+  AO_int_load_read(const volatile unsigned *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned result;
 
 #if defined(AO_HAVE_int_compare_and_swap_full) \
     && !defined(AO_HAVE_int_load_full)
   AO_INLINE unsigned
-  AO_int_load_full(const volatile unsigned *addr)
+  AO_int_load_full(const volatile unsigned *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned result;
 
     && !defined(AO_HAVE_int_load_acquire)
   AO_INLINE unsigned
   AO_int_load_acquire(const volatile unsigned *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned result;
 
 
 #if defined(AO_HAVE_int_compare_and_swap) && !defined(AO_HAVE_int_load)
   AO_INLINE unsigned
-  AO_int_load(const volatile unsigned *addr)
+  AO_int_load(const volatile unsigned *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned result;
 
     && !defined(AO_HAVE_int_store_write)
   AO_INLINE void
   AO_int_store_write(volatile unsigned *addr, unsigned new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old_val;
 
 #if defined(AO_HAVE_int_compare_and_swap) && !defined(AO_HAVE_int_store)
   AO_INLINE void
   AO_int_store(volatile unsigned *addr, unsigned new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old_val;
 
     && !defined(AO_HAVE_int_store_release)
   AO_INLINE void
   AO_int_store_release(volatile unsigned *addr, unsigned new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old_val;
 
     && !defined(AO_HAVE_int_store_full)
   AO_INLINE void
   AO_int_store_full(volatile unsigned *addr, unsigned new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     unsigned old_val;
 
     && !defined(AO_HAVE_load_read)
 # define AO_CAS_BASED_LOAD_READ
   AO_INLINE AO_t
-  AO_load_read(const volatile AO_t *addr)
+  AO_load_read(const volatile AO_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t result;
 
 #if defined(AO_HAVE_compare_and_swap_full) \
     && !defined(AO_HAVE_load_full)
   AO_INLINE AO_t
-  AO_load_full(const volatile AO_t *addr)
+  AO_load_full(const volatile AO_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t result;
 
     && !defined(AO_HAVE_load_acquire)
   AO_INLINE AO_t
   AO_load_acquire(const volatile AO_t *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t result;
 
 
 #if defined(AO_HAVE_compare_and_swap) && !defined(AO_HAVE_load)
   AO_INLINE AO_t
-  AO_load(const volatile AO_t *addr)
+  AO_load(const volatile AO_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t result;
 
     && !defined(AO_HAVE_store_write)
   AO_INLINE void
   AO_store_write(volatile AO_t *addr, AO_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old_val;
 
 #if defined(AO_HAVE_compare_and_swap) && !defined(AO_HAVE_store)
   AO_INLINE void
   AO_store(volatile AO_t *addr, AO_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old_val;
 
     && !defined(AO_HAVE_store_release)
   AO_INLINE void
   AO_store_release(volatile AO_t *addr, AO_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old_val;
 
     && !defined(AO_HAVE_store_full)
   AO_INLINE void
   AO_store_full(volatile AO_t *addr, AO_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_t old_val;
 
     && !defined(AO_HAVE_double_load_read)
 # define AO_double_CAS_BASED_LOAD_READ
   AO_INLINE AO_double_t
-  AO_double_load_read(const volatile AO_double_t *addr)
+  AO_double_load_read(const volatile AO_double_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t result;
 
 #if defined(AO_HAVE_double_compare_and_swap_full) \
     && !defined(AO_HAVE_double_load_full)
   AO_INLINE AO_double_t
-  AO_double_load_full(const volatile AO_double_t *addr)
+  AO_double_load_full(const volatile AO_double_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t result;
 
     && !defined(AO_HAVE_double_load_acquire)
   AO_INLINE AO_double_t
   AO_double_load_acquire(const volatile AO_double_t *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t result;
 
 
 #if defined(AO_HAVE_double_compare_and_swap) && !defined(AO_HAVE_double_load)
   AO_INLINE AO_double_t
-  AO_double_load(const volatile AO_double_t *addr)
+  AO_double_load(const volatile AO_double_t *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t result;
 
     && !defined(AO_HAVE_double_store_write)
   AO_INLINE void
   AO_double_store_write(volatile AO_double_t *addr, AO_double_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t old_val;
 
 #if defined(AO_HAVE_double_compare_and_swap) && !defined(AO_HAVE_double_store)
   AO_INLINE void
   AO_double_store(volatile AO_double_t *addr, AO_double_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t old_val;
 
     && !defined(AO_HAVE_double_store_release)
   AO_INLINE void
   AO_double_store_release(volatile AO_double_t *addr, AO_double_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t old_val;
 
     && !defined(AO_HAVE_double_store_full)
   AO_INLINE void
   AO_double_store_full(volatile AO_double_t *addr, AO_double_t new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     AO_double_t old_val;
 
index 328f43e..99e96a1 100644 (file)
     && !defined(AO_HAVE_XSIZE_load_read)
 # define AO_XSIZE_CAS_BASED_LOAD_READ
   AO_INLINE XCTYPE
-  AO_XSIZE_load_read(const volatile XCTYPE *addr)
+  AO_XSIZE_load_read(const volatile XCTYPE *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE result;
 
 #if defined(AO_HAVE_XSIZE_compare_and_swap_full) \
     && !defined(AO_HAVE_XSIZE_load_full)
   AO_INLINE XCTYPE
-  AO_XSIZE_load_full(const volatile XCTYPE *addr)
+  AO_XSIZE_load_full(const volatile XCTYPE *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE result;
 
     && !defined(AO_HAVE_XSIZE_load_acquire)
   AO_INLINE XCTYPE
   AO_XSIZE_load_acquire(const volatile XCTYPE *addr)
+                                                AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE result;
 
 
 #if defined(AO_HAVE_XSIZE_compare_and_swap) && !defined(AO_HAVE_XSIZE_load)
   AO_INLINE XCTYPE
-  AO_XSIZE_load(const volatile XCTYPE *addr)
+  AO_XSIZE_load(const volatile XCTYPE *addr) AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE result;
 
     && !defined(AO_HAVE_XSIZE_store_write)
   AO_INLINE void
   AO_XSIZE_store_write(volatile XCTYPE *addr, XCTYPE new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old_val;
 
 #if defined(AO_HAVE_XSIZE_compare_and_swap) && !defined(AO_HAVE_XSIZE_store)
   AO_INLINE void
   AO_XSIZE_store(volatile XCTYPE *addr, XCTYPE new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old_val;
 
     && !defined(AO_HAVE_XSIZE_store_release)
   AO_INLINE void
   AO_XSIZE_store_release(volatile XCTYPE *addr, XCTYPE new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old_val;
 
     && !defined(AO_HAVE_XSIZE_store_full)
   AO_INLINE void
   AO_XSIZE_store_full(volatile XCTYPE *addr, XCTYPE new_val)
-                                                AO_ATTR_NO_SANITIZE_MEMORY
+                        AO_ATTR_NO_SANITIZE_MEMORY AO_ATTR_NO_SANITIZE_THREAD
   {
     XCTYPE old_val;
 
index 3ab1f76..f3c7d87 100644 (file)
          || (defined(__x86_64__) && !defined(__ILP32__) \
              && (!(AO_CLANG_PREREQ(3, 5) \
                    || defined(AO_PREFER_BUILTIN_ATOMICS)) \
-                 || defined(AO_ADDRESS_SANITIZER))))
+                 || defined(AO_ADDRESS_SANITIZER) \
+                 || defined(AO_THREAD_SANITIZER))))
     /* As of clang-3.8 i686 (NDK r11c), it requires -latomic for all    */
     /* the double-wide operations.  Same for clang-3.4/x64.  For now,   */
     /* we fall back to the non-intrinsic implementation by default.     */
-    /* As of clang-3.8, double-wide arguments are incorrectly passed to */
-    /* atomic intrinsic operations for x64 target if ASan is enabled.   */
+    /* As of clang-4.0, double-wide arguments are incorrectly passed to */
+    /* atomic intrinsic operations for x64 target if ASan/TSan enabled. */
 #   define AO_SKIPATOMIC_double_compare_and_swap_ANY
 #   define AO_SKIPATOMIC_double_load
 #   define AO_SKIPATOMIC_double_load_acquire
index 4748e6a..30703ab 100644 (file)
@@ -310,7 +310,11 @@ AO_malloc(size_t sz)
     add_chunk_as(chunk, log_sz);
     result = AO_stack_pop(AO_free_list+log_sz);
   }
-  *result = log_sz;
+# ifdef AO_THREAD_SANITIZER
+    AO_store(result, log_sz);
+# else
+    *result = log_sz;
+# endif
 # ifdef AO_TRACE_MALLOC
     fprintf(stderr, "%p: AO_malloc(%lu) = %p\n",
             (void *)pthread_self(), (unsigned long)sz, (void *)(result + 1));
@@ -327,7 +331,11 @@ AO_free(void *p)
   if (0 == p) return;
 
   base = (AO_t *)p - 1;
-  log_sz = (int)(*base);
+# ifdef AO_THREAD_SANITIZER
+    log_sz = (int)AO_load(base);
+# else
+    log_sz = (int)(*base);
+# endif
 # ifdef AO_TRACE_MALLOC
     fprintf(stderr, "%p: AO_free(%p sz:%lu)\n", (void *)pthread_self(), p,
             log_sz > LOG_MAX_SIZE ? (unsigned)log_sz : 1UL << log_sz);
index c14c47c..e1df09c 100644 (file)
@@ -48,7 +48,7 @@
 /* pointers with extra bits "or"ed into the low order bits.             */
 void
 AO_stack_push_explicit_aux_release(volatile AO_t *list, AO_t *x,
-                                   AO_stack_aux *a)
+                                   AO_stack_aux *a) AO_ATTR_NO_SANITIZE_THREAD
 {
   AO_t x_bits = (AO_t)x;
   AO_t next;
@@ -94,7 +94,7 @@ AO_stack_push_explicit_aux_release(volatile AO_t *list, AO_t *x,
   do
     {
       next = AO_load(list);
-      *x = next;
+      *x = next; /* data race is OK here */
     }
   while (AO_EXPECT_FALSE(!AO_compare_and_swap_release(list, next, x_bits)));
 }
@@ -203,12 +203,13 @@ AO_stack_pop_explicit_aux_acquire(volatile AO_t *list, AO_stack_aux * a)
 #endif
 
 void AO_stack_push_release(AO_stack_t *list, AO_t *element)
+                                                AO_ATTR_NO_SANITIZE_THREAD
 {
     AO_t next;
 
     do {
       next = AO_load(&(list -> ptr));
-      *element = next;
+      *element = next; /* data race is OK here */
     } while (AO_EXPECT_FALSE(!AO_compare_and_swap_release(&(list -> ptr),
                                                       next, (AO_t)element)));
     /* This uses a narrow CAS here, an old optimization suggested       */
@@ -221,7 +222,7 @@ void AO_stack_push_release(AO_stack_t *list, AO_t *element)
 #   endif
 }
 
-AO_t *AO_stack_pop_acquire(AO_stack_t *list)
+AO_t *AO_stack_pop_acquire(AO_stack_t *list) AO_ATTR_NO_SANITIZE_THREAD
 {
 #   ifdef __clang__
       AO_t *volatile cptr;
@@ -238,7 +239,7 @@ AO_t *AO_stack_pop_acquire(AO_stack_t *list)
       cversion = AO_load_acquire(&(list -> version));
       cptr = (AO_t *)AO_load(&(list -> ptr));
       if (cptr == 0) return 0;
-      next = *cptr;
+      next = *cptr; /* data race is OK here */
     } while (AO_EXPECT_FALSE(!AO_compare_double_and_swap_double_release(list,
                                         cversion, (AO_t)cptr,
                                         cversion+1, (AO_t)next)));
index 5a25dac..8b57bd6 100644 (file)
@@ -137,6 +137,12 @@ AO_TS_t lock = AO_TS_INITIALIZER;
 unsigned long locked_counter;
 volatile unsigned long junk = 13;
 
+void do_junk(void) AO_ATTR_NO_SANITIZE_THREAD
+{
+  junk *= 17;
+  junk *= 19;
+}
+
 void * test_and_set_thr(void * id)
 {
   unsigned long i;
@@ -164,8 +170,7 @@ void * test_and_set_thr(void * id)
       --locked_counter;
       AO_CLEAR(&lock);
       /* Spend a bit of time outside the lock. */
-        junk *= 17;
-        junk *= 17;
+      do_junk();
     }
   return 0;
 }
index e9d924a..b51d4fb 100644 (file)
@@ -68,9 +68,9 @@ typedef struct list_node {
         int data;
 } ln;
 
-ln *cons(int d, ln *tail)
+ln *cons(int d, ln *tail) AO_ATTR_NO_SANITIZE_THREAD
 {
-  static size_t extra = 0;
+  static size_t extra = 0; /* data race in extra is OK */
   size_t my_extra = extra;
   ln *result;
   int * extras;