chenBright opened a new pull request, #3551:
URL: https://github.com/apache/brpc/pull/3551

   ### What problem does this PR solve?
   
   Issue Number: resolve 
   
   Problem Summary:
   
   There are two related bugs between `butex_wait()` and 
`TaskGroup::interrupt()`,
     both exposed by `ButexTest.join_cant_be_wakeup` under ASAN in CI.
   
     1. Uninitialized `ButexPthreadWaiter::container` crash.
   
        In `butex_wait_from_pthread()`, the on-stack `ButexPthreadWaiter pw` is
        published to `TaskMeta::current_waiter` before its `container` field is
        initialized. A concurrent `TaskGroup::interrupt()` consumes 
`current_waiter`
        and calls `erase_from_butex()` on it, which loads `container` and, if 
it is
        non-null, dereferences it as a `Butex*` and locks it. Reading 
uninitialized
        stack memory there makes `erase_from_butex()` lock garbage and crash. 
The
        ASAN report from 
[CI](https://github.com/apache/brpc/actions/runs/34238048209/job/102100771652):
   
   
   ```text
   ==41009==ERROR: AddressSanitizer: SEGV on unknown address 0x7fceda8e0440 (pc 
0x7fced9c1ef7a bp 0x7fff5f9a44c0 sp 0x7fff5f9a4420 T0)
   ==41009==The signal is caused by a WRITE memory access.
       #0 0x7fced9c1ef7a in std::__atomic_base<unsigned 
char>::exchange(unsigned char, std::memory_order) 
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/atomic_base.h:506:9
       #1 0x7fced9c1ef7a in butil::static_atomic<unsigned 
char>::exchange(unsigned char, std::memory_order) 
/home/runner/work/brpc/brpc/./src/butil/atomicops.h:295:52
       #2 0x7fced9c1ef7a in bthread::internal::FastPthreadMutex::try_lock() 
/home/runner/work/brpc/brpc/src/bthread/mutex.cpp:1150:32
       #3 0x7fced9c1ef7a in bthread::internal::FastPthreadMutex::lock() 
/home/runner/work/brpc/brpc/src/bthread/mutex.cpp:1140:9
       #4 0x7fced9c1ef7a in 
bthread::internal::pthread_mutex_lock_internal(bthread::internal::FastPthreadMutex*,
 timespec const*) /home/runner/work/brpc/brpc/src/bthread/mutex.cpp:861:16
       #5 0x7fced9c1ef7a in int 
bthread::internal::pthread_mutex_lock_impl<bthread::internal::FastPthreadMutex>(bthread::internal::FastPthreadMutex*,
 timespec const*) /home/runner/work/brpc/brpc/src/bthread/mutex.cpp:884:16
       #6 0x7fced9c1ef7a in bthread::FastPthreadMutex::lock() 
/home/runner/work/brpc/brpc/src/bthread/mutex.cpp:1180:5
       #7 0x7fced9bf3826 in 
std::lock_guard<bthread::FastPthreadMutex>::lock_guard(bthread::FastPthreadMutex&)
 
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_mutex.h:229:19
       #8 0x7fced9bf3826 in bthread::erase_from_butex(bthread::ButexWaiter*, 
bool, bthread::WaiterState) 
/home/runner/work/brpc/brpc/src/bthread/butex.cpp:524:9
       #9 0x7fced9c979f3 in bthread::TaskGroup::interrupt(unsigned long, 
bthread::TaskControl*) 
/home/runner/work/brpc/brpc/src/bthread/task_group.cpp:1176:9
       #10 0x4e8134 in (anonymous 
namespace)::ButexTest_join_cant_be_wakeup_Test::TestBody() 
/home/runner/work/brpc/brpc/test/bthread_butex_unittest.cpp:303:9
       #11 0x528bfe in void 
testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, 
void>(testing::Test*, void (testing::Test::*)(), char const*) 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x528bfe)
       #12 0x51cce5 in testing::Test::Run() 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x51cce5)
       #13 0x51ce64 in testing::TestInfo::Run() 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x51ce64)
       #14 0x51d418 in testing::TestSuite::Run() 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x51d418)
       #15 0x51db1e in testing::internal::UnitTestImpl::RunAllTests() 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x51db1e)
       #16 0x5291c6 in bool 
testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,
 bool>(testing::internal::UnitTestImpl*, bool 
(testing::internal::UnitTestImpl::*)(), char const*) 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x5291c6)
       #17 0x51cf2b in testing::UnitTest::Run() 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x51cf2b)
       #18 0x42cab3 in main 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x42cab3)
       #19 0x7fced8829d8f in __libc_start_call_main 
csu/../sysdeps/nptl/libc_start_call_main.h:58:16
       #20 0x7fced8829e3f in __libc_start_main csu/../csu/libc-start.c:392:3
       #21 0x42cb14 in _start 
(/home/runner/work/brpc/brpc/test/bthread_butex_unittest+0x42cb14)
   
   AddressSanitizer can not provide additional info.
   SUMMARY: AddressSanitizer: SEGV 
/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/atomic_base.h:506:9
 in std::__atomic_base<unsigned char>::exchange(unsigned char, 
std::memory_order)
   ```
   
     2. Lost interruption.
   
     Even with `container` initialized to nullptr, checking 
`TaskMeta::interrupted`
     and publishing `container` were not atomic with respect to `interrupt()`.
     `interrupt()` sets `interrupted` and consumes `current_waiter` under
     `version_lock`. If it slips in between the check and the publish, its
     `erase_from_butex()` observes `container` still nullptr (a no-op) and no 
one
     wakes `pw` up, so the waiter blocks forever (or until timeout) and the
     interruption is lost.
   
   ### What is changed and the side effects?
   
   Changed:
   
     * Initialize `pw.container` to nullptr before `pw` is published to
       `current_waiter`, so a racing `interrupt()` observes either nullptr (its
       `erase_from_butex()` is a no-op) or a valid `Butex*`, never stack 
garbage.
     * Keep `container` nullptr until `pw` is queued, then check `interrupted` 
and
       publish `container` together under `version_lock`. This makes the check 
and
       the publish atomic with respect to `interrupt()`, so `interrupt()` can 
only
       land on either side of them, never in between. This mirrors the existing
       logic in `wait_for_butex()` for bthread waiters.
   
   Side effects:
   - Performance effects:
   
   - Breaking backward compatibility: 
   
   ---
   ### Check List:
   - Please make sure your changes are compilable.
   - When providing us with a new feature, it is best to add related tests.
   - Please follow [Contributor Covenant Code of 
Conduct](https://github.com/apache/brpc/blob/master/CODE_OF_CONDUCT.md).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to