does thread-sanitizer trace + parse Linux syscall ( SYS_futex ... ) calls + _Atomic operations ?

137 views
Skip to first unread message

Jason Vas Dias

unread,
May 24, 2018, 6:03:24 PM5/24/18
to thread-s...@googlegroups.com

Good day -

I have a very simple Lock C++ class implemented with inline
methods in a header file, that uses the linux futex() syscall:
syscall( SYS_FUTEX, uaddr, FUTEX_WAIT /* OR */ FUTEX_WAKE ...)
and
__atomic_sub_fetch( uaddr, x, _MM_SEQ_CST_ )
and
__atomic_add_fetch( uaddr, x, _MM_SEQ_CST_ )
and
__atomic_load_n( uaddr )
-
( these are GCC builtin atomics as used by C++'s 'include <atomic>' )
to implement mutexes and condition variables
without using pthread_mutex* / pthread_cond*.

This does seem to work robustly & efficiently , but instrumenting with
GCC 7.3 's '-fsanitize=thread -ltsan' options finds problems at each
futex protected critical section, which I have every other reason to
believe are truly mutually exclusive - eg. :

WARNING: ThreadSanitizer: data race (pid=7390)
Write of size 1 at 0x00000060b3e0 by thread T1:

(it passes -fsanitize=address + -fsanitize=undefined, so I thought
I'd try -fsanitize=thread) .

Now I'm wondering, does thread sanitizer recognize that futex() calls,
when invoked via syscall(SYS_FUTEX,..) impose hard ordering contraints
and are blocking ? It does not seem to. Or is it telling me that somehow
the code is broken and genuine simultaneous access to the protected
memory area accessed by both threads is definitely taking place ?

The test programs for my Lock class do check for data validity, and would
definitely be triggered if any data corruption / invalid data
occurred, which would definitely happen if a writer updated a value
that the reader did not read , and are not triggered, but tsan reports
all critical section accesses to protected regions by the code as races
- I do not think they are genuine races - is tsan following what syscall
(SYS_FUTEX...) is doing?

Thanks for any responses, Best Regards,
Jason



Dmitry Vyukov

unread,
May 26, 2018, 4:00:31 AM5/26/18
to thread-s...@googlegroups.com, Evgenii Stepanov
Hi Jason,

ThreadSanitizer does not intercept syscall(SYS_FUTEX) and so it misses
any synchronization this call provides.

+Evgenii, do you remember why we don't intercept syscall function? Our
syscall machinery seems to require manual annotations, but for syscall
we could do it all automatically.

Jason, as a workaround you could add manual annotations around futex
calls, along the following lines:

#ifdef THREAD_SANITIZER
extern "C" void __tsan_acquire(void *addr);
extern "C" void __tsan_release(void *addr);
#else
inline void __tsan_acquire(void *addr) {}
inline void __tsan_release(void *addr) {}
#endif

__tsan_release(addr);
syscall(FUTEX_WAKE, addr, ...);

if (syscall(FUTEX_WAIT, addr, ...) == 0)
__tsan_acquire(addr);


And then compile with -fsanitize=thread -DTHREAD_SANITIZER.

Latest clang versions provide tsan_interface.h header with these
functions, but I don't know if gcc provides it.

Evgenii Stepanov

unread,
May 29, 2018, 1:21:03 PM5/29/18
to Dmitry Vyukov, thread-s...@googlegroups.com
We don't intercept syscall() because our syscall hooks are keyed off
the call name, not the call number. We'd need a number-to-name table
to apply them.
Reply all
Reply to author
Forward
0 new messages