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]