[libcxx-commits] [PATCH] D122864: [libc++] Avoid lifetime UB in __thread_local_data()

Vitaly Buka via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Mon Apr 18 21:05:10 PDT 2022


vitalybuka updated this revision to Diff 423523.
vitalybuka added a comment.

rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122864/new/

https://reviews.llvm.org/D122864

Files:
  libcxx/src/thread.cpp
  libcxx/test/libcxx/thread/thread.threads/create_late.pass.cpp


Index: libcxx/test/libcxx/thread/thread.threads/create_late.pass.cpp
===================================================================
--- /dev/null
+++ libcxx/test/libcxx/thread/thread.threads/create_late.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++03
+
+#include <mutex>
+
+#include "make_test_thread.h"
+
+void func() {}
+
+struct T {
+  ~T() {
+    // __thread_local_data is expected to be destroyed as it was created
+    // from the main(). Now trigger another access.
+    support::make_test_thread(func).join();
+  }
+} t;
+
+int main(int, char**) {
+  // Triggers construction of __thread_local_data.
+  support::make_test_thread(func).join();
+
+  return 0;
+}
Index: libcxx/src/thread.cpp
===================================================================
--- libcxx/src/thread.cpp
+++ libcxx/src/thread.cpp
@@ -115,8 +115,13 @@
 __thread_specific_ptr<__thread_struct>&
 __thread_local_data()
 {
-    static __thread_specific_ptr<__thread_struct> __p;
-    return __p;
+  // Even though __thread_specific_ptr's destructor doesn't actually destroy
+  // anything (see comments there), we can't call it at all because threads may
+  // outlive the static variable and calling its destructor means accessing an
+  // object outside of its lifetime, which is UB.
+  alignas(__thread_specific_ptr<__thread_struct>) static char __b[sizeof(__thread_specific_ptr<__thread_struct>)];
+  static __thread_specific_ptr<__thread_struct>* __p = new (__b) __thread_specific_ptr<__thread_struct>();
+  return *__p;
 }
 
 // __thread_struct_imp


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D122864.423523.patch
Type: text/x-patch
Size: 1963 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20220419/6cac18ef/attachment.bin>


More information about the libcxx-commits mailing list