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