https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78158
--- Comment #2 from Dmitry Vyukov <dvyukov at google dot com> ---
With -O0 there is huge potential for ODR violations. E.g. code contains:
401774: e8 f3 06 00 00 callq 401e6c
<std::atomic<bool>::operator bool() const>
If some other non-instrumented library contains a non-instrumented copy of the
function, we can get false positives.
However, the problem seems to be different.
With -O1 I see that compare_exchange is compiled correctly (redirected into
tsan runtime):
if(not readers.compare_exchange_weak(local_readers, local_readers +
1))
401721: 8d 53 01 lea 0x1(%rbx),%edx
memory_order __b1 = __m1 & __memory_order_mask;
__glibcxx_assert(__b2 != memory_order_release);
__glibcxx_assert(__b2 != memory_order_acq_rel);
__glibcxx_assert(__b2 <= __b1);
return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1, __m1, __m2);
401724: 41 b8 05 00 00 00 mov $0x5,%r8d
40172a: b9 05 00 00 00 mov $0x5,%ecx
40172f: 48 8d 74 24 3c lea 0x3c(%rsp),%rsi
401734: bf 68 26 60 00 mov $0x602668,%edi
401739: e8 82 fd ff ff callq 4014c0
<__tsan_atomic32_compare_exchange_weak@plt>
40173e: 84 c0 test %al,%al
401740: 74 a5 je 4016e7 <fun()+0x71>
401742: bb e8 03 00 00 mov $0x3e8,%ebx
}
However with -O0, there is plain inlined LOCK CMPXCHG instruction without any
tsan instrumentation:
if(not readers.compare_exchange_weak(local_readers, local_readers +
1))
4017e4: 48 8d 85 60 ff ff ff lea -0xa0(%rbp),%rax
4017eb: 48 89 c7 mov %rax,%rdi
4017ee: e8 1d fb ff ff callq 401310 <__tsan_read4@plt>
4017f3: 8b 85 60 ff ff ff mov -0xa0(%rbp),%eax
4017f9: 83 c0 01 add $0x1,%eax
4017fc: 89 45 c0 mov %eax,-0x40(%rbp)
4017ff: c7 45 bc 05 00 00 00 movl $0x5,-0x44(%rbp)
_GLIBCXX_ALWAYS_INLINE bool
compare_exchange_weak(__int_type& __i1, __int_type __i2,
memory_order __m = memory_order_seq_cst) noexcept
{
return compare_exchange_weak(__i1, __i2, __m,
401806: 8b 45 bc mov -0x44(%rbp),%eax
401809: 89 c7 mov %eax,%edi
40180b: e8 cb 05 00 00 callq 401ddb
<std::__cmpexch_failure_order(std::memory_order)>
401810: 89 c2 mov %eax,%edx
401812: 48 c7 45 b0 e4 55 60 movq $0x6055e4,-0x50(%rbp)
401819: 00
40181a: 48 8d 85 60 ff ff ff lea -0xa0(%rbp),%rax
401821: 48 89 45 a8 mov %rax,-0x58(%rbp)
401825: 8b 45 c0 mov -0x40(%rbp),%eax
401828: 89 45 a4 mov %eax,-0x5c(%rbp)
40182b: 8b 45 bc mov -0x44(%rbp),%eax
40182e: 89 45 a0 mov %eax,-0x60(%rbp)
401831: 89 55 9c mov %edx,-0x64(%rbp)
_GLIBCXX_ALWAYS_INLINE bool
compare_exchange_weak(__int_type& __i1, __int_type __i2,
memory_order __m1, memory_order __m2) noexcept
{
memory_order __b2 = __m2 & __memory_order_mask;
401834: 8b 45 9c mov -0x64(%rbp),%eax
401837: be ff ff 00 00 mov $0xffff,%esi
40183c: 89 c7 mov %eax,%edi
40183e: e8 5e 05 00 00 callq 401da1
<std::operator&(std::memory_order, std::__memory_order_modifier)>
401843: 89 45 98 mov %eax,-0x68(%rbp)
memory_order __b1 = __m1 & __memory_order_mask;
401846: 8b 45 a0 mov -0x60(%rbp),%eax
401849: be ff ff 00 00 mov $0xffff,%esi
40184e: 89 c7 mov %eax,%edi
401850: e8 4c 05 00 00 callq 401da1
<std::operator&(std::memory_order, std::__memory_order_modifier)>
401855: 89 45 94 mov %eax,-0x6c(%rbp)
__glibcxx_assert(__b2 != memory_order_release);
__glibcxx_assert(__b2 != memory_order_acq_rel);
__glibcxx_assert(__b2 <= __b1);
return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1, __m1, __m2);
401858: 8b 4d a4 mov -0x5c(%rbp),%ecx
40185b: 48 8b 75 b0 mov -0x50(%rbp),%rsi
40185f: 48 8b 55 a8 mov -0x58(%rbp),%rdx
401863: 8b 02 mov (%rdx),%eax
401865: f0 0f b1 0e lock cmpxchg %ecx,(%rsi)
401869: 89 c1 mov %eax,%ecx
40186b: 0f 94 c0 sete %al
40186e: 84 c0 test %al,%al
401870: 75 02 jne 401874 <fun()+0x12d>
401872: 89 0a mov %ecx,(%rdx)
401874: 83 f0 01 xor $0x1,%eax
401877: 84 c0 test %al,%al
401879: 74 2e je 4018a9 <fun()+0x162>
continue;
Jakub, do you see how -O0 can lead to inlined but non-instrumented
compare_exchange?