https://github.com/higher-performance created 
https://github.com/llvm/llvm-project/pull/136602

This is to partially address issue #112782.

>From f86372ac92bda26a99bf0b17acd226d677853a47 Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.git...@gmail.com>
Date: Mon, 21 Apr 2025 16:09:44 -0400
Subject: [PATCH] Add bugprone-uninitialized-thread-local to detect when
 thread-locals might be accessed without initialization

This is to partially address issue #112782.
---
 .../bugprone/BugproneTidyModule.cpp           |  1 +
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 .../UninitializedThreadLocalCheck.cpp         | 46 +++++++++++++++++++
 .../bugprone/UninitializedThreadLocalCheck.h  | 43 +++++++++++++++++
 .../bugprone/uninitialized-thread-local.cpp   | 16 +++++++
 5 files changed, 107 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/uninitialized-thread-local.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index b780a85bdf3fe..7b75b26c97fdb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -91,6 +91,7 @@
 #include "UndelegatedConstructorCheck.h"
 #include "UnhandledExceptionAtNewCheck.h"
 #include "UnhandledSelfAssignmentCheck.h"
+#include "UninitializedThreadLocalCheck.h"
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index e310ea9c94543..56ef12f48987a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   InaccurateEraseCheck.cpp
   IncorrectEnableIfCheck.cpp
   IncorrectEnableSharedFromThisCheck.cpp
+  UninitializedThreadLocalCheck.cpp
   UnintendedCharOstreamOutputCheck.cpp
   ReturnConstRefFromParameterCheck.cpp
   SuspiciousStringviewDataUsageCheck.cpp
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.cpp
new file mode 100644
index 0000000000000..c6037944caff3
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.cpp
@@ -0,0 +1,46 @@
+//===--- UninitializedThreadLocalCheck.cpp - clang-tidy
+//--------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "UninitializedThreadLocalCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UninitializedThreadLocalCheck::UninitializedThreadLocalCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {}
+
+void UninitializedThreadLocalCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      declRefExpr(
+          // Fast check -- bail out quickly before slower filters
+          to(varDecl(hasThreadStorageDuration(),
+                     hasDeclContext(functionDecl()))),
+          forCallable(decl().bind("ctx")),
+          to(varDecl(unless(hasDeclContext(equalsBoundNode("ctx"))))))
+          .bind("declref"),
+      this);
+}
+
+void UninitializedThreadLocalCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
+  diag(E->getLocation(),
+       "variable '%0' might not have been initialized on the current thread. "
+       "To guarantee prior initialization on the same thread that performs the 
"
+       "access, consider capturing the address of the variable in the same "
+       "block as its initialization, then use the captured address to the "
+       "desired code.")
+      << E;
+}
+
+} // namespace clang::tidy::bugprone
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.h
new file mode 100644
index 0000000000000..4f31b0984ebc2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UninitializedThreadLocalCheck.h
@@ -0,0 +1,43 @@
+//===--- UninitializedThreadLocalCheck.cpp - clang-tidy
+//--------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "UninitializedThreadLocalCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UninitializedThreadLocalCheck::UninitializedThreadLocalCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {}
+
+void UninitializedThreadLocalCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      declRefExpr(to(varDecl(hasThreadStorageDuration()).bind("var")),
+                  hasAncestor(functionDecl(
+                      unless(hasDescendant(varDecl(equalsBoundNode("var")))))))
+          .bind("declref"),
+      this);
+}
+
+void UninitializedThreadLocalCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
+  diag(E->getLocation(),
+       "variable '%0' might not have been initialized on the current thread. "
+       "To guarantee prior initialization on the same thread that performs the 
"
+       "access, consider capturing the address of the variable in the same "
+       "block as its initialization, then use the captured address to the "
+       "desired code.")
+      << E;
+}
+
+} // namespace clang::tidy::bugprone
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/uninitialized-thread-local.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/uninitialized-thread-local.cpp
new file mode 100644
index 0000000000000..59f773f843a24
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/uninitialized-thread-local.cpp
@@ -0,0 +1,16 @@
+// RUN: %check_clang_tidy %s bugprone-uninitialized-thread-local %t
+
+thread_local int global_tls = 1;
+
+int main() {
+  thread_local int local_tls = 2;
+  {
+    ++global_tls; // no warning
+    ++local_tls; // no warning
+  }
+  auto f = []() {
+    return local_tls + global_tls;
+    // CHECK-MESSAGES: [[@LINE-1]]:12: warning: variable 'local_tls' might not 
have been initialized on the current thread.
+  };
+  return f();
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to