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?

Reply via email to