This is an automated email from the ASF dual-hosted git repository.

chenBright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 36e729b7 Validate thread key generation during TLS cleanup (#3648)
36e729b7 is described below

commit 36e729b718ea0d259b7d05e23cc76daef2debc48
Author: nkysg <[email protected]>
AuthorDate: Sat Oct 24 22:09:51 2026 +0800

    Validate thread key generation during TLS cleanup (#3648)
---
 src/butil/thread_key.cpp     | 17 ++++++++++++-----
 src/butil/thread_key.h       |  7 +++++++
 test/thread_key_unittest.cpp | 21 +++++++++++++++++++++
 3 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/src/butil/thread_key.cpp b/src/butil/thread_key.cpp
index 94c432a0..22c57216 100644
--- a/src/butil/thread_key.cpp
+++ b/src/butil/thread_key.cpp
@@ -40,6 +40,17 @@ static std::deque<size_t>* g_free_ids = nullptr;
 static std::vector<ThreadKeyInfo>* g_thread_keys = nullptr;
 static __thread std::vector<ThreadKeyTLS>* thread_key_tls_data = nullptr;
 
+void detail::DestroyThreadKeyData(const std::vector<ThreadKeyInfo>& keys,
+                                  std::vector<ThreadKeyTLS>* tls_data) {
+    for (size_t i = 0; i < tls_data->size(); ++i) {
+        const ThreadKeyTLS& tls = (*tls_data)[i];
+        if (i < keys.size() && tls.seq == keys[i].seq &&
+            !KEY_UNUSED(keys[i].seq) && keys[i].dtor) {
+            keys[i].dtor(tls.data);
+        }
+    }
+}
+
 ThreadKey& ThreadKey::operator=(ThreadKey&& other) noexcept {
     if (this == &other) {
         return *this;
@@ -66,11 +77,7 @@ static void DestroyTlsData() {
                           g_thread_keys->begin(),
                           g_thread_keys->end());
     }
-    for (size_t i = 0; i < thread_key_tls_data->size(); ++i) {
-        if (!KEY_UNUSED(dummy_keys[i].seq) && dummy_keys[i].dtor) {
-            dummy_keys[i].dtor((*thread_key_tls_data)[i].data);
-        }
-    }
+    detail::DestroyThreadKeyData(dummy_keys, thread_key_tls_data);
     delete thread_key_tls_data;
     thread_key_tls_data = nullptr;
 }
diff --git a/src/butil/thread_key.h b/src/butil/thread_key.h
index 47abcabe..d4e8cd1c 100644
--- a/src/butil/thread_key.h
+++ b/src/butil/thread_key.h
@@ -87,6 +87,13 @@ struct ThreadKeyTLS {
     void* data; // User data.
 };
 
+namespace detail {
+
+void DestroyThreadKeyData(const std::vector<ThreadKeyInfo>& keys,
+                          std::vector<ThreadKeyTLS>* tls_data);
+
+}  // namespace detail
+
 // pthread_key_xxx implication without num limit of key.
 int thread_key_create(ThreadKey& thread_key, DtorFunction dtor);
 int thread_key_delete(ThreadKey& thread_key);
diff --git a/test/thread_key_unittest.cpp b/test/thread_key_unittest.cpp
index 681bb3e2..427e575a 100644
--- a/test/thread_key_unittest.cpp
+++ b/test/thread_key_unittest.cpp
@@ -112,6 +112,27 @@ TEST(ThreadLocalTest, thread_key_seq) {
     }
 }
 
+void CountThreadKeyDtor(void* arg) {
+    ++*static_cast<int*>(arg);
+}
+
+TEST(ThreadLocalTest, thread_key_destructor_matches_sequence) {
+    int dtor_calls = 0;
+    std::vector<ThreadKeyTLS> tls_data(1);
+    tls_data[0].seq = 1;
+    tls_data[0].data = &dtor_calls;
+
+    std::vector<butil::ThreadKeyInfo> keys(1);
+    keys[0].seq = 3;
+    keys[0].dtor = CountThreadKeyDtor;
+    detail::DestroyThreadKeyData(keys, &tls_data);
+    EXPECT_EQ(0, dtor_calls);
+
+    tls_data[0].seq = keys[0].seq;
+    detail::DestroyThreadKeyData(keys, &tls_data);
+    EXPECT_EQ(1, dtor_calls);
+}
+
 void* THreadKeyCreateAndDeleteFunc(void*) {
     while (!g_stopped) {
         ThreadKey key;


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

Reply via email to