[clang] Fix some static initialization race-conditions (PR #181367)
Richard Dzenis via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 13 07:44:17 PST 2026
https://github.com/RIscRIpt updated https://github.com/llvm/llvm-project/pull/181367
>From b13d48cd827f2eed3fdc3c1eef7d0495a6f8bd70 Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Fri, 13 Feb 2026 15:46:24 +0200
Subject: [PATCH 1/7] [clang][StaticAnalyzer] Fix static init in findKnownClass
Prior to this patch two threads running in findKnownClass could result
in a race condition.
---
.../Checkers/BasicObjCFoundationChecks.cpp | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index e682c4ef80896..0c48d77679226 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -70,16 +70,12 @@ enum FoundationClass {
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
bool IncludeSuperclasses = true) {
- static llvm::StringMap<FoundationClass> Classes;
- if (Classes.empty()) {
- Classes["NSArray"] = FC_NSArray;
- Classes["NSDictionary"] = FC_NSDictionary;
- Classes["NSEnumerator"] = FC_NSEnumerator;
- Classes["NSNull"] = FC_NSNull;
- Classes["NSOrderedSet"] = FC_NSOrderedSet;
- Classes["NSSet"] = FC_NSSet;
- Classes["NSString"] = FC_NSString;
- }
+ static llvm::StringMap<FoundationClass> Classes{
+ {"NSArray", FC_NSArray}, {"NSDictionary", FC_NSDictionary},
+ {"NSEnumerator", FC_NSEnumerator}, {"NSNull", FC_NSNull},
+ {"NSOrderedSet", FC_NSOrderedSet}, {"NSSet", FC_NSSet},
+ {"NSString", FC_NSString},
+ };
// FIXME: Should we cache this at all?
FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
>From 53df8baa67bc7e4dffb8232d4fe936e5d312720f Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Fri, 13 Feb 2026 15:51:41 +0200
Subject: [PATCH 2/7] [clang][CodeGen] Correctly restore diagnostic handler in
HandleTranslationUnit
Prior to this patch an early exit from HandleTranslationUnit could
result in not restoring previous diagnostic handler.
---
clang/lib/CodeGen/CodeGenAction.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index a5ef4ac9d361d..29dcabd1b0971 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -248,6 +248,8 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) {
LLVMContext &Ctx = getModule()->getContext();
std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler =
Ctx.getDiagnosticHandler();
+ llvm::scope_exit RestoreDiagnosticHandler(
+ [&]() { Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); });
Ctx.setDiagnosticHandler(std::make_unique<ClangDiagnosticHandler>(
CodeGenOpts, this));
@@ -311,8 +313,6 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) {
C.getTargetInfo().getDataLayoutString(), getModule(),
Action, FS, std::move(AsmOutStream), this);
- Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler));
-
if (OptRecordFile)
OptRecordFile->keep();
}
>From af2c8d2a30d3e6484a565743c054996e083b9870 Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Thu, 12 Feb 2026 20:07:16 +0200
Subject: [PATCH 3/7] [clang][Stmt] Fix StmtClassNameTable array initialization
Prior to this patch there was a race condition when two threads check
`if (Initialized)` at the same time.
---
clang/lib/AST/Stmt.cpp | 43 +++++++++++++++++++++---------------------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 5b745dd3c43f5..5715546d31dbe 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -57,26 +57,19 @@ using namespace clang;
#define ABSTRACT_STMT(STMT)
#include "clang/AST/StmtNodes.inc"
-static struct StmtClassNameTable {
+struct StmtClassNameTable {
const char *Name;
unsigned Counter;
unsigned Size;
-} StmtClassInfo[Stmt::lastStmtConstant+1];
+};
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
- static bool Initialized = false;
- if (Initialized)
- return StmtClassInfo[E];
-
- // Initialize the table on the first use.
- Initialized = true;
+ static StmtClassNameTable stmtClassInfo[Stmt::lastStmtConstant + 1] = {
#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) \
- StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
- StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
+#define STMT(CLASS, PARENT) {#CLASS, 0, sizeof(CLASS)},
#include "clang/AST/StmtNodes.inc"
-
- return StmtClassInfo[E];
+ };
+ return stmtClassInfo[E];
}
void *Stmt::operator new(size_t bytes, const ASTContext& C,
@@ -85,7 +78,7 @@ void *Stmt::operator new(size_t bytes, const ASTContext& C,
}
const char *Stmt::getStmtClassName() const {
- return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
+ return getStmtInfoTableEntry(static_cast<StmtClass>(StmtBits.sClass)).Name;
}
// Check that no statement / expression class is polymorphic. LLVM style RTTI
@@ -113,19 +106,25 @@ void Stmt::PrintStats() {
unsigned sum = 0;
llvm::errs() << "\n*** Stmt/Expr Stats:\n";
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
- if (StmtClassInfo[i].Name == nullptr) continue;
- sum += StmtClassInfo[i].Counter;
+ StmtClassNameTable &entry =
+ getStmtInfoTableEntry(static_cast<Stmt::StmtClass>(i));
+ if (entry.Name == nullptr)
+ continue;
+ sum += entry.Counter;
}
llvm::errs() << " " << sum << " stmts/exprs total.\n";
sum = 0;
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
- if (StmtClassInfo[i].Name == nullptr) continue;
- if (StmtClassInfo[i].Counter == 0) continue;
- llvm::errs() << " " << StmtClassInfo[i].Counter << " "
- << StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size
- << " each (" << StmtClassInfo[i].Counter*StmtClassInfo[i].Size
+ StmtClassNameTable &entry =
+ getStmtInfoTableEntry(static_cast<Stmt::StmtClass>(i));
+ if (entry.Name == nullptr)
+ continue;
+ if (entry.Counter == 0)
+ continue;
+ llvm::errs() << " " << entry.Counter << " " << entry.Name << ", "
+ << entry.Size << " each (" << entry.Counter * entry.Size
<< " bytes)\n";
- sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
+ sum += entry.Counter * entry.Size;
}
llvm::errs() << "Total bytes = " << sum << "\n";
>From 139a461214436e61187dbe2df4ad6d48b4fcd264 Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Thu, 12 Feb 2026 20:27:30 +0200
Subject: [PATCH 4/7] [clang][ParsedAttrInfo] Fix race condition in
getAttributePluginInstances
Prior to this patch two threads could enter under if (empty()) check.
---
clang/lib/Basic/ParsedAttrInfo.cpp | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Basic/ParsedAttrInfo.cpp b/clang/lib/Basic/ParsedAttrInfo.cpp
index 16fa314b642b9..d5b17b34b6e3a 100644
--- a/clang/lib/Basic/ParsedAttrInfo.cpp
+++ b/clang/lib/Basic/ParsedAttrInfo.cpp
@@ -20,13 +20,16 @@ using namespace clang;
LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
+static std::list<std::unique_ptr<ParsedAttrInfo>> instantiateEntries() {
+ std::list<std::unique_ptr<ParsedAttrInfo>> Instances;
+ for (const auto &It : ParsedAttrInfoRegistry::entries())
+ Instances.emplace_back(It.instantiate());
+ return Instances;
+}
+
const std::list<std::unique_ptr<ParsedAttrInfo>> &
clang::getAttributePluginInstances() {
- static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>>
- PluginAttrInstances;
- if (PluginAttrInstances->empty())
- for (const auto &It : ParsedAttrInfoRegistry::entries())
- PluginAttrInstances->emplace_back(It.instantiate());
-
- return *PluginAttrInstances;
+ static std::list<std::unique_ptr<ParsedAttrInfo>> Instances =
+ instantiateEntries();
+ return Instances;
}
>From 067184ee614dca2b521996fd9f65731c1bfbcfff Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Fri, 13 Feb 2026 17:03:08 +0200
Subject: [PATCH 5/7] fixup! [clang][StaticAnalyzer] Fix static init in
findKnownClass
---
clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 0c48d77679226..f226f80aa441f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -70,7 +70,7 @@ enum FoundationClass {
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
bool IncludeSuperclasses = true) {
- static llvm::StringMap<FoundationClass> Classes{
+ static const llvm::StringMap<FoundationClass> Classes{
{"NSArray", FC_NSArray}, {"NSDictionary", FC_NSDictionary},
{"NSEnumerator", FC_NSEnumerator}, {"NSNull", FC_NSNull},
{"NSOrderedSet", FC_NSOrderedSet}, {"NSSet", FC_NSSet},
>From a723ab26a9968e1bc96f1fe4be106bbf7fe0d22b Mon Sep 17 00:00:00 2001
From: Richard Dzenis <rixript at gmail.com>
Date: Fri, 13 Feb 2026 17:31:04 +0200
Subject: [PATCH 6/7] fixup! [clang][Stmt] Fix StmtClassNameTable array
initialization
Co-authored-by: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
---
clang/lib/AST/Stmt.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 5715546d31dbe..2793fb763f5d0 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -106,7 +106,7 @@ void Stmt::PrintStats() {
unsigned sum = 0;
llvm::errs() << "\n*** Stmt/Expr Stats:\n";
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
- StmtClassNameTable &entry =
+ const StmtClassNameTable &entry =
getStmtInfoTableEntry(static_cast<Stmt::StmtClass>(i));
if (entry.Name == nullptr)
continue;
@@ -115,7 +115,7 @@ void Stmt::PrintStats() {
llvm::errs() << " " << sum << " stmts/exprs total.\n";
sum = 0;
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
- StmtClassNameTable &entry =
+ const StmtClassNameTable &entry =
getStmtInfoTableEntry(static_cast<Stmt::StmtClass>(i));
if (entry.Name == nullptr)
continue;
>From 53cf6d7a380b06f680b5b1d229d0aed795adf679 Mon Sep 17 00:00:00 2001
From: Richard Dzenis <richard at dzenis.dev>
Date: Fri, 13 Feb 2026 17:43:46 +0200
Subject: [PATCH 7/7] fixup! [clang][Stmt] Fix StmtClassNameTable array
initialization
---
clang/lib/AST/Stmt.cpp | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 2793fb763f5d0..18fe2bc5eb01e 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -40,6 +40,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <array>
#include <cassert>
#include <cstring>
#include <optional>
@@ -64,11 +65,16 @@ struct StmtClassNameTable {
};
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
- static StmtClassNameTable stmtClassInfo[Stmt::lastStmtConstant + 1] = {
+ static std::array<StmtClassNameTable, Stmt::lastStmtConstant + 1>
+ stmtClassInfo = []() {
+ std::array<StmtClassNameTable, Stmt::lastStmtConstant + 1> table;
#define ABSTRACT_STMT(STMT)
-#define STMT(CLASS, PARENT) {#CLASS, 0, sizeof(CLASS)},
+#define STMT(CLASS, PARENT) \
+ table[static_cast<unsigned>(Stmt::CLASS##Class)].Name = #CLASS; \
+ table[static_cast<unsigned>(Stmt::CLASS##Class)].Size = sizeof(CLASS);
#include "clang/AST/StmtNodes.inc"
- };
+ return table;
+ }();
return stmtClassInfo[E];
}
More information about the cfe-commits
mailing list