[libc-commits] [libc] 6f1a9ed - [LIBC] Fix incorrect behavior with pthread_key_t when value was nullptr

Noah Goldstein via libc-commits libc-commits at lists.llvm.org
Wed Apr 19 17:55:09 PDT 2023


Author: Noah Goldstein
Date: 2023-04-19T19:54:56-05:00
New Revision: 6f1a9ed072de612584a90adf3469744781da17fc

URL: https://github.com/llvm/llvm-project/commit/6f1a9ed072de612584a90adf3469744781da17fc
DIFF: https://github.com/llvm/llvm-project/commit/6f1a9ed072de612584a90adf3469744781da17fc.diff

LOG: [LIBC] Fix incorrect behavior with pthread_key_t when value was nullptr

We should not call destructor if value is nullptr.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D148291

Added: 
    

Modified: 
    libc/src/__support/threads/thread.cpp
    libc/test/integration/src/pthread/pthread_tss_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/threads/thread.cpp b/libc/src/__support/threads/thread.cpp
index b2680ecc0bda0..03e93a42fb04c 100644
--- a/libc/src/__support/threads/thread.cpp
+++ b/libc/src/__support/threads/thread.cpp
@@ -151,7 +151,8 @@ void call_atexit_callbacks(ThreadAttributes *attrib) {
   attrib->atexit_callback_mgr->call();
   for (size_t i = 0; i < TSS_KEY_COUNT; ++i) {
     TSSValueUnit &unit = tss_values[i];
-    if (unit.dtor != nullptr)
+    // Both dtor and value need to nonnull to call dtor
+    if (unit.dtor != nullptr && unit.payload != nullptr)
       unit.dtor(unit.payload);
   }
 }

diff  --git a/libc/test/integration/src/pthread/pthread_tss_test.cpp b/libc/test/integration/src/pthread/pthread_tss_test.cpp
index 5d649026db0e6..b5843d226ff10 100644
--- a/libc/test/integration/src/pthread/pthread_tss_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_tss_test.cpp
@@ -21,16 +21,19 @@ static constexpr int THREAD_DATA_INITVAL = 0x1234;
 static constexpr int THREAD_DATA_FINIVAL = 0x4321;
 static constexpr int THREAD_RUN_VAL = 0x600D;
 
-int child_thread_data = THREAD_DATA_INITVAL;
-int main_thread_data = THREAD_DATA_INITVAL;
+static int child_thread_data = THREAD_DATA_INITVAL;
+static int main_thread_data = THREAD_DATA_INITVAL;
 
-pthread_key_t key;
-void dtor(void *data) {
+static pthread_key_t key;
+static void dtor(void *data) {
   auto *v = reinterpret_cast<int *>(data);
   *v = THREAD_DATA_FINIVAL;
 }
 
-void *func(void *obj) {
+// Used to test that we don't call the destructor when the mapped value in NULL.
+static void dtor_failure(void *) { ASSERT_TRUE(false); }
+
+static void *func(void *obj) {
   ASSERT_EQ(__llvm_libc::pthread_setspecific(key, &child_thread_data), 0);
   int *d = reinterpret_cast<int *>(__llvm_libc::pthread_getspecific(key));
   ASSERT_TRUE(d != nullptr);
@@ -40,7 +43,14 @@ void *func(void *obj) {
   return nullptr;
 }
 
-TEST_MAIN() {
+static void *func_null_val(void *) {
+  // null value, we should not call dtor
+  ASSERT_EQ(__llvm_libc::pthread_setspecific(key, nullptr), 0);
+  ASSERT_EQ(__llvm_libc::pthread_getspecific(key), nullptr);
+  return nullptr;
+}
+
+static void standard_usage_test() {
   ASSERT_EQ(__llvm_libc::pthread_key_create(&key, &dtor), 0);
   ASSERT_EQ(__llvm_libc::pthread_setspecific(key, &main_thread_data), 0);
   int *d = reinterpret_cast<int *>(__llvm_libc::pthread_getspecific(key));
@@ -56,7 +66,20 @@ TEST_MAIN() {
   ASSERT_EQ(retval, nullptr);
   ASSERT_EQ(arg, THREAD_RUN_VAL);
   ASSERT_EQ(child_thread_data, THREAD_DATA_FINIVAL);
+  ASSERT_EQ(__llvm_libc::pthread_key_delete(key), 0);
+}
 
+static void null_value_test() {
+  pthread_t th;
+  ASSERT_EQ(__llvm_libc::pthread_key_create(&key, &dtor_failure), 0);
+  ASSERT_EQ(__llvm_libc::pthread_create(&th, nullptr, &func_null_val, nullptr),
+            0);
+  ASSERT_EQ(__llvm_libc::pthread_join(th, nullptr), 0);
   ASSERT_EQ(__llvm_libc::pthread_key_delete(key), 0);
+}
+
+TEST_MAIN() {
+  standard_usage_test();
+  null_value_test();
   return 0;
 }


        


More information about the libc-commits mailing list