Skip to content

Fix bthread id butex state races - #3689

Open
songgaoye wants to merge 2 commits into
apache:masterfrom
songgaoye:fix/bthread-id-join-race
Open

songgaoye wants to merge 2 commits into
apache:masterfrom
songgaoye:fix/bthread-id-join-race

Conversation

@songgaoye

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: resolve

Problem Summary:

  • bthread_id accesses butex state words as plain uint32_t values even though butex manages them as atomic state. Concurrent bthread_id_join() and bthread_id_unlock_and_destroy() can therefore form a C++ data race.
    What is changed and the side effects?

Changed:

  • Store ID butex state as butil::atomic.
  • Centralize atomic version-word access helpers.
  • Add a concurrent join/destroy regression test.

Side effects:

  • Performance effects:

  • Breaking backward compatibility:


Check List:

@songgaoye
songgaoye force-pushed the fix/bthread-id-join-race branch from 8e93fe6 to 58f5f92 Compare October 28, 2026 15:58
@songgaoye

songgaoye commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

run tsan on master branch.

WARNING: ThreadSanitizer: data race (pid=552747)
  Write of size 4 at 0x729400000040 by main thread:
    #0 bthread_id_unlock_and_destroy
       /home/ysg/Github/brpc-tsan-join-destroy/src/bthread/id.cpp:630:17
    #1 (anonymous namespace)::BthreadIdTest_join_races_with_destroy_Test::TestBody()
       /home/ysg/Github/brpc-tsan-join-destroy/test/bthread_id_unittest.cpp:142:9
    #2 testing::Test::Run()
    #3 testing::TestInfo::Run()
    #4 testing::TestSuite::Run()
    #5 testing::internal::UnitTestImpl::RunAllTests()
    #6 testing::UnitTest::Run()
    #7 RUN_ALL_TESTS()
    #8 main

  Previous atomic read of size 4 at 0x729400000040 by thread T2:
    #0 std::__atomic_base<int>::load(std::memory_order) const
       /usr/include/c++/13/bits/atomic_base.h:505:9
    #1 bthread::butex_wait(void*, int, timespec const*, bool)
       /home/ysg/Github/brpc-tsan-join-destroy/src/bthread/butex.cpp:755:18
    #2 bthread_id_join
       /home/ysg/Github/brpc-tsan-join-destroy/src/bthread/id.cpp:530:13
    #3 (anonymous namespace)::join_race_waiter(void*)
       /home/ysg/Github/brpc-tsan-join-destroy/test/bthread_id_unittest.cpp:124:5

  Thread T2 (tid=552759, running) created by main thread at:
    #0 pthread_create
    #1 (anonymous namespace)::BthreadIdTest_join_races_with_destroy_Test::TestBody()
       /home/ysg/Github/brpc-tsan-join-destroy/test/bthread_id_unittest.cpp:136:9

@songgaoye
songgaoye force-pushed the fix/bthread-id-join-race branch from 58f5f92 to ed9a32f Compare October 28, 2026 16:12
Comment thread test/bthread_id_unittest.cpp Resolved
@songgaoye
songgaoye force-pushed the fix/bthread-id-join-race branch from 287a9cc to 420d3ef Compare October 29, 2026 15:29
@songgaoye
songgaoye force-pushed the fix/bthread-id-join-race branch from 420d3ef to 73f925c Compare October 29, 2026 15:59
@darion-yaphet

Copy link
Copy Markdown
Contributor

Thanks for the follow-up.

The new join_races_with_destroy test addresses my earlier concern: the waiter now signals only after the join path has already loaded join_butex, and destroy runs before butex_wait, so the race window is the reported.

From the bthread id / butex side this LGTM. CI is green on this head; approving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants