Skip to content

Commit 20f7588

Browse files
Add bugprone-uninitialized-thread-local to detect when thread-locals might be accessed without initialization
This is to partially address issue #112782.
1 parent 4b98955 commit 20f7588

File tree

5 files changed

+97
-0
lines changed

5 files changed

+97
-0
lines changed

clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#include "UndelegatedConstructorCheck.h"
9292
#include "UnhandledExceptionAtNewCheck.h"
9393
#include "UnhandledSelfAssignmentCheck.h"
94+
#include "UninitializedThreadLocalCheck.h"
9495
#include "UnintendedCharOstreamOutputCheck.h"
9596
#include "UniquePtrArrayMismatchCheck.h"
9697
#include "UnsafeFunctionsCheck.h"

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC
3030
InaccurateEraseCheck.cpp
3131
IncorrectEnableIfCheck.cpp
3232
IncorrectEnableSharedFromThisCheck.cpp
33+
UninitializedThreadLocalCheck.cpp
3334
UnintendedCharOstreamOutputCheck.cpp
3435
ReturnConstRefFromParameterCheck.cpp
3536
SuspiciousStringviewDataUsageCheck.cpp
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- UninitializedThreadLocalCheck.cpp - clang-tidy
2+
//--------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "UninitializedThreadLocalCheck.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/Lex/Lexer.h"
13+
14+
using namespace clang::ast_matchers;
15+
16+
namespace clang::tidy::bugprone {
17+
18+
UninitializedThreadLocalCheck::UninitializedThreadLocalCheck(
19+
StringRef Name, ClangTidyContext *Context)
20+
: ClangTidyCheck(Name, Context) {}
21+
22+
void UninitializedThreadLocalCheck::registerMatchers(MatchFinder *Finder) {
23+
Finder->addMatcher(
24+
declRefExpr(
25+
// Fast check -- bail out quickly before slower filters
26+
to(varDecl(hasThreadStorageDuration(),
27+
hasDeclContext(functionDecl()))),
28+
forCallable(decl().bind("ctx")),
29+
to(varDecl(unless(hasDeclContext(equalsBoundNode("ctx"))))))
30+
.bind("declref"),
31+
this);
32+
}
33+
34+
void UninitializedThreadLocalCheck::check(
35+
const MatchFinder::MatchResult &Result) {
36+
const auto *E = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
37+
diag(E->getLocation(),
38+
"variable '%0' might not have been initialized on the current thread. "
39+
"To guarantee prior initialization on the same thread that performs the "
40+
"access, consider capturing the address of the variable in the same "
41+
"block as its initialization, then use the captured address to the "
42+
"desired code.")
43+
<< E;
44+
}
45+
46+
} // namespace clang::tidy::bugprone
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===--- UninitializedThreadLocalCheck.cpp - Clang tidy tool --------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINITIALIZEDTHREADLOCALCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINITIALIZEDTHREADLOCALCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::runtime {
15+
16+
// Finds accesses to thread_local variables that might occur prior to
17+
// initialization.
18+
class UninitializedThreadLocalCheck : public ClangTidyCheck {
19+
public:
20+
UninitializedThreadLocalCheck(StringRef Name, ClangTidyContext *Context);
21+
22+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
23+
return LangOpts.CPlusPlus;
24+
}
25+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
26+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
27+
28+
private:
29+
};
30+
31+
} // namespace clang::tidy::runtime
32+
33+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNINITIALIZEDTHREADLOCALCHECK_H
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %check_clang_tidy %s bugprone-uninitialized-thread-local %t
2+
3+
thread_local int global_tls = 1;
4+
5+
int main() {
6+
thread_local int local_tls = 2;
7+
{
8+
++global_tls; // no warning
9+
++local_tls; // no warning
10+
}
11+
auto f = []() {
12+
return local_tls + global_tls;
13+
// CHECK-MESSAGES: [[@LINE-1]]:12: warning: variable 'local_tls' might not have been initialized on the current thread.
14+
};
15+
return f();
16+
}

0 commit comments

Comments
 (0)