Reapply "[clang] Fix some static initialization race-conditions" (#182020)

This reverts d4b574266132e08ff585facf2e0e01995082999f,
and reapplies d7f32f1fbf83da2faa4acdcaf2a4d4885a2d068c.

Original commit message:
- clang/StaticAnalyzer: fix static init in findKnownClass. Prior to this
  patch two threads running in findKnownClass could result in a race
  condition.
- 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/ParsedAttrInfo: fix race condition in
  getAttributePluginInstances. Prior to this patch two threads could
  enter `if(empty())` check.
- 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.
This commit is contained in:
Richard Dzenis 2026-02-18 18:36:47 +02:00 committed by GitHub
parent 537e09b70d
commit 5fbbd41342
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 40 deletions

View File

@ -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>
@ -57,25 +58,23 @@ 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 std::array<StmtClassNameTable, Stmt::lastStmtConstant + 1>
StmtClassInfo = [] {
std::array<StmtClassNameTable, Stmt::lastStmtConstant + 1> Table{};
#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) \
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];
}
@ -85,7 +84,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 +112,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;
const 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
const 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";

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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 const 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());