Skip to content

Commit 9c2718a

Browse files
committed
Thread safety analysis: Fix a bug in handling temporary constructors
Extends the lifetime of the map `ConstructedObjects` to be of the whole CFG so that the map can connect temporary Ctor and Dtor in different CFG blocks.
1 parent 668a4a2 commit 9c2718a

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

clang/lib/Analysis/ThreadSafety.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,8 @@ class ThreadSafetyAnalyzer {
10101010
ThreadSafetyHandler &Handler;
10111011
const FunctionDecl *CurrentFunction;
10121012
LocalVariableMap LocalVarMap;
1013+
// Maps constructed objects to `this` placeholder prior to initialization.
1014+
llvm::SmallDenseMap<const Expr *, til::LiteralPtr *> ConstructedObjects;
10131015
FactManager FactMan;
10141016
std::vector<CFGBlockInfo> BlockInfo;
10151017

@@ -1543,8 +1545,6 @@ class BuildLockset : public ConstStmtVisitor<BuildLockset> {
15431545
FactSet FSet;
15441546
// The fact set for the function on exit.
15451547
const FactSet &FunctionExitFSet;
1546-
/// Maps constructed objects to `this` placeholder prior to initialization.
1547-
llvm::SmallDenseMap<const Expr *, til::LiteralPtr *> ConstructedObjects;
15481548
LocalVariableMap::Context LVarCtx;
15491549
unsigned CtxIndex;
15501550

@@ -1808,7 +1808,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
18081808
std::pair<til::LiteralPtr *, StringRef> Placeholder =
18091809
Analyzer->SxBuilder.createThisPlaceholder(Exp);
18101810
[[maybe_unused]] auto inserted =
1811-
ConstructedObjects.insert({Exp, Placeholder.first});
1811+
Analyzer->ConstructedObjects.insert({Exp, Placeholder.first});
18121812
assert(inserted.second && "Are we visiting the same expression again?");
18131813
if (isa<CXXConstructExpr>(Exp))
18141814
Self = Placeholder.first;
@@ -2128,10 +2128,10 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
21282128
E = EWC->getSubExpr()->IgnoreParens();
21292129
E = UnpackConstruction(E);
21302130

2131-
if (auto Object = ConstructedObjects.find(E);
2132-
Object != ConstructedObjects.end()) {
2131+
if (auto Object = Analyzer->ConstructedObjects.find(E);
2132+
Object != Analyzer->ConstructedObjects.end()) {
21332133
Object->second->setClangDecl(VD);
2134-
ConstructedObjects.erase(Object);
2134+
Analyzer->ConstructedObjects.erase(Object);
21352135
}
21362136
}
21372137
}
@@ -2140,11 +2140,11 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
21402140
void BuildLockset::VisitMaterializeTemporaryExpr(
21412141
const MaterializeTemporaryExpr *Exp) {
21422142
if (const ValueDecl *ExtD = Exp->getExtendingDecl()) {
2143-
if (auto Object =
2144-
ConstructedObjects.find(UnpackConstruction(Exp->getSubExpr()));
2145-
Object != ConstructedObjects.end()) {
2143+
if (auto Object = Analyzer->ConstructedObjects.find(
2144+
UnpackConstruction(Exp->getSubExpr()));
2145+
Object != Analyzer->ConstructedObjects.end()) {
21462146
Object->second->setClangDecl(ExtD);
2147-
ConstructedObjects.erase(Object);
2147+
Analyzer->ConstructedObjects.erase(Object);
21482148
}
21492149
}
21502150
}
@@ -2487,15 +2487,15 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
24872487

24882488
// Clean up constructed object even if there are no attributes to
24892489
// keep the number of objects in limbo as small as possible.
2490-
if (auto Object = LocksetBuilder.ConstructedObjects.find(
2490+
if (auto Object = ConstructedObjects.find(
24912491
TD.getBindTemporaryExpr()->getSubExpr());
2492-
Object != LocksetBuilder.ConstructedObjects.end()) {
2492+
Object != ConstructedObjects.end()) {
24932493
const auto *DD = TD.getDestructorDecl(AC.getASTContext());
24942494
if (DD->hasAttrs())
24952495
// TODO: the location here isn't quite correct.
24962496
LocksetBuilder.handleCall(nullptr, DD, Object->second,
24972497
TD.getBindTemporaryExpr()->getEndLoc());
2498-
LocksetBuilder.ConstructedObjects.erase(Object);
2498+
ConstructedObjects.erase(Object);
24992499
}
25002500
break;
25012501
}

clang/test/SemaCXX/warn-thread-safety-analysis.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,8 @@ struct TestScopedLockable {
17021702

17031703
bool getBool();
17041704

1705+
bool lock2Bool(MutexLock);
1706+
17051707
void foo1() {
17061708
MutexLock mulock(&mu1);
17071709
a = 5;
@@ -1718,6 +1720,12 @@ struct TestScopedLockable {
17181720
MutexLock{&mu1}, a = 5;
17191721
}
17201722

1723+
void temporary_cfg(int x) {
1724+
// test the case where a pair of temporary Ctor and Dtor is in different CFG blocks
1725+
lock2Bool(MutexLock{&mu1}) || x;
1726+
MutexLock{&mu1}; // no-warn
1727+
}
1728+
17211729
void lifetime_extension() {
17221730
const MutexLock &mulock = MutexLock(&mu1);
17231731
a = 5;

0 commit comments

Comments
 (0)