File indexing completed on 2026-05-10 08:36:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
0022 #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
0023
0024 #include "clang/AST/Decl.h"
0025 #include "clang/Analysis/Analyses/PostOrderCFGView.h"
0026 #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
0027 #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
0028 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
0029 #include "clang/Analysis/AnalysisDeclContext.h"
0030 #include "clang/Analysis/CFG.h"
0031 #include "clang/Basic/LLVM.h"
0032 #include "llvm/ADT/DenseMap.h"
0033 #include "llvm/ADT/PointerIntPair.h"
0034 #include "llvm/ADT/PointerUnion.h"
0035 #include "llvm/ADT/SmallVector.h"
0036 #include "llvm/Support/Casting.h"
0037 #include <sstream>
0038 #include <string>
0039 #include <utility>
0040 #include <vector>
0041
0042 namespace clang {
0043
0044 class AbstractConditionalOperator;
0045 class ArraySubscriptExpr;
0046 class BinaryOperator;
0047 class CallExpr;
0048 class CastExpr;
0049 class CXXDestructorDecl;
0050 class CXXMemberCallExpr;
0051 class CXXOperatorCallExpr;
0052 class CXXThisExpr;
0053 class DeclRefExpr;
0054 class DeclStmt;
0055 class Expr;
0056 class MemberExpr;
0057 class Stmt;
0058 class UnaryOperator;
0059
0060 namespace threadSafety {
0061
0062
0063 namespace sx {
0064
0065 inline bool equals(const til::SExpr *E1, const til::SExpr *E2) {
0066 return til::EqualsComparator::compareExprs(E1, E2);
0067 }
0068
0069 inline bool matches(const til::SExpr *E1, const til::SExpr *E2) {
0070
0071
0072
0073 if (isa<til::Wildcard>(E1))
0074 return isa<til::Wildcard>(E2);
0075 if (isa<til::Wildcard>(E2))
0076 return isa<til::Wildcard>(E1);
0077
0078 return til::MatchComparator::compareExprs(E1, E2);
0079 }
0080
0081 inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
0082 const auto *PE1 = dyn_cast_or_null<til::Project>(E1);
0083 if (!PE1)
0084 return false;
0085 const auto *PE2 = dyn_cast_or_null<til::Project>(E2);
0086 if (!PE2)
0087 return false;
0088 return PE1->clangDecl() == PE2->clangDecl();
0089 }
0090
0091 inline std::string toString(const til::SExpr *E) {
0092 std::stringstream ss;
0093 til::StdPrinter::print(E, ss);
0094 return ss.str();
0095 }
0096
0097 }
0098
0099
0100
0101
0102 class CFGVisitor {
0103
0104 void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
0105
0106
0107 void enterCFGBlock(const CFGBlock *B) {}
0108
0109
0110 bool visitPredecessors() { return true; }
0111
0112
0113 void handlePredecessor(const CFGBlock *Pred) {}
0114
0115
0116 void handlePredecessorBackEdge(const CFGBlock *Pred) {}
0117
0118
0119 void enterCFGBlockBody(const CFGBlock *B) {}
0120
0121
0122 void handleStatement(const Stmt *S) {}
0123
0124
0125 void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
0126
0127
0128 void exitCFGBlockBody(const CFGBlock *B) {}
0129
0130
0131 bool visitSuccessors() { return true; }
0132
0133
0134 void handleSuccessor(const CFGBlock *Succ) {}
0135
0136
0137 void handleSuccessorBackEdge(const CFGBlock *Succ) {}
0138
0139
0140 void exitCFGBlock(const CFGBlock *B) {}
0141
0142
0143 void exitCFG(const CFGBlock *Last) {}
0144 };
0145
0146
0147 class CFGWalker {
0148 public:
0149 CFGWalker() = default;
0150
0151
0152
0153 bool init(AnalysisDeclContext &AC) {
0154 ACtx = &AC;
0155 CFGraph = AC.getCFG();
0156 if (!CFGraph)
0157 return false;
0158
0159
0160 if (!isa_and_nonnull<NamedDecl>(AC.getDecl()))
0161 return false;
0162
0163 SortedGraph = AC.getAnalysis<PostOrderCFGView>();
0164 if (!SortedGraph)
0165 return false;
0166
0167 return true;
0168 }
0169
0170
0171 template <class Visitor>
0172 void walk(Visitor &V) {
0173 PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
0174
0175 V.enterCFG(CFGraph, getDecl(), &CFGraph->getEntry());
0176
0177 for (const auto *CurrBlock : *SortedGraph) {
0178 VisitedBlocks.insert(CurrBlock);
0179
0180 V.enterCFGBlock(CurrBlock);
0181
0182
0183 if (V.visitPredecessors()) {
0184 SmallVector<CFGBlock*, 4> BackEdges;
0185
0186 for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
0187 SE = CurrBlock->pred_end();
0188 SI != SE; ++SI) {
0189 if (*SI == nullptr)
0190 continue;
0191
0192 if (!VisitedBlocks.alreadySet(*SI)) {
0193 BackEdges.push_back(*SI);
0194 continue;
0195 }
0196 V.handlePredecessor(*SI);
0197 }
0198
0199 for (auto *Blk : BackEdges)
0200 V.handlePredecessorBackEdge(Blk);
0201 }
0202
0203 V.enterCFGBlockBody(CurrBlock);
0204
0205
0206 for (const auto &BI : *CurrBlock) {
0207 switch (BI.getKind()) {
0208 case CFGElement::Statement:
0209 V.handleStatement(BI.castAs<CFGStmt>().getStmt());
0210 break;
0211
0212 case CFGElement::AutomaticObjectDtor: {
0213 CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
0214 auto *DD = const_cast<CXXDestructorDecl *>(
0215 AD.getDestructorDecl(ACtx->getASTContext()));
0216 auto *VD = const_cast<VarDecl *>(AD.getVarDecl());
0217 V.handleDestructorCall(VD, DD);
0218 break;
0219 }
0220 default:
0221 break;
0222 }
0223 }
0224
0225 V.exitCFGBlockBody(CurrBlock);
0226
0227
0228 if (V.visitSuccessors()) {
0229 SmallVector<CFGBlock*, 8> ForwardEdges;
0230
0231
0232 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
0233 SE = CurrBlock->succ_end();
0234 SI != SE; ++SI) {
0235 if (*SI == nullptr)
0236 continue;
0237
0238 if (!VisitedBlocks.alreadySet(*SI)) {
0239 ForwardEdges.push_back(*SI);
0240 continue;
0241 }
0242 V.handleSuccessorBackEdge(*SI);
0243 }
0244
0245 for (auto *Blk : ForwardEdges)
0246 V.handleSuccessor(Blk);
0247 }
0248
0249 V.exitCFGBlock(CurrBlock);
0250 }
0251 V.exitCFG(&CFGraph->getExit());
0252 }
0253
0254 const CFG *getGraph() const { return CFGraph; }
0255 CFG *getGraph() { return CFGraph; }
0256
0257 const NamedDecl *getDecl() const {
0258 return dyn_cast<NamedDecl>(ACtx->getDecl());
0259 }
0260
0261 const PostOrderCFGView *getSortedGraph() const { return SortedGraph; }
0262
0263 private:
0264 CFG *CFGraph = nullptr;
0265 AnalysisDeclContext *ACtx = nullptr;
0266 PostOrderCFGView *SortedGraph = nullptr;
0267 };
0268
0269
0270
0271
0272 class CapabilityExpr {
0273 private:
0274
0275 llvm::PointerIntPair<const til::SExpr *, 1, bool> CapExpr;
0276
0277
0278 StringRef CapKind;
0279
0280 public:
0281 CapabilityExpr() : CapExpr(nullptr, false) {}
0282 CapabilityExpr(const til::SExpr *E, StringRef Kind, bool Neg)
0283 : CapExpr(E, Neg), CapKind(Kind) {}
0284
0285
0286 template <typename T> CapabilityExpr(const til::SExpr *, T, bool) = delete;
0287
0288 const til::SExpr *sexpr() const { return CapExpr.getPointer(); }
0289 StringRef getKind() const { return CapKind; }
0290 bool negative() const { return CapExpr.getInt(); }
0291
0292 CapabilityExpr operator!() const {
0293 return CapabilityExpr(CapExpr.getPointer(), CapKind, !CapExpr.getInt());
0294 }
0295
0296 bool equals(const CapabilityExpr &other) const {
0297 return (negative() == other.negative()) &&
0298 sx::equals(sexpr(), other.sexpr());
0299 }
0300
0301 bool matches(const CapabilityExpr &other) const {
0302 return (negative() == other.negative()) &&
0303 sx::matches(sexpr(), other.sexpr());
0304 }
0305
0306 bool matchesUniv(const CapabilityExpr &CapE) const {
0307 return isUniversal() || matches(CapE);
0308 }
0309
0310 bool partiallyMatches(const CapabilityExpr &other) const {
0311 return (negative() == other.negative()) &&
0312 sx::partiallyMatches(sexpr(), other.sexpr());
0313 }
0314
0315 const ValueDecl* valueDecl() const {
0316 if (negative() || sexpr() == nullptr)
0317 return nullptr;
0318 if (const auto *P = dyn_cast<til::Project>(sexpr()))
0319 return P->clangDecl();
0320 if (const auto *P = dyn_cast<til::LiteralPtr>(sexpr()))
0321 return P->clangDecl();
0322 return nullptr;
0323 }
0324
0325 std::string toString() const {
0326 if (negative())
0327 return "!" + sx::toString(sexpr());
0328 return sx::toString(sexpr());
0329 }
0330
0331 bool shouldIgnore() const { return sexpr() == nullptr; }
0332
0333 bool isInvalid() const { return isa_and_nonnull<til::Undefined>(sexpr()); }
0334
0335 bool isUniversal() const { return isa_and_nonnull<til::Wildcard>(sexpr()); }
0336 };
0337
0338
0339 class SExprBuilder {
0340 public:
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 struct CallingContext {
0351
0352 CallingContext *Prev;
0353
0354
0355 const NamedDecl *AttrDecl;
0356
0357
0358 llvm::PointerUnion<const Expr *, til::SExpr *> SelfArg = nullptr;
0359
0360
0361 unsigned NumArgs = 0;
0362
0363
0364 llvm::PointerUnion<const Expr *const *, til::SExpr *> FunArgs = nullptr;
0365
0366
0367 bool SelfArrow = false;
0368
0369 CallingContext(CallingContext *P, const NamedDecl *D = nullptr)
0370 : Prev(P), AttrDecl(D) {}
0371 };
0372
0373 SExprBuilder(til::MemRegionRef A) : Arena(A) {
0374
0375 SelfVar = new (Arena) til::Variable(nullptr);
0376 SelfVar->setKind(til::Variable::VK_SFun);
0377 }
0378
0379
0380
0381 CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
0382 const Expr *DeclExp,
0383 til::SExpr *Self = nullptr);
0384
0385 CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
0386
0387
0388 til::LiteralPtr *createVariable(const VarDecl *VD);
0389
0390
0391 std::pair<til::LiteralPtr *, StringRef>
0392 createThisPlaceholder(const Expr *Exp);
0393
0394
0395
0396
0397 til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
0398 til::SCFG *buildCFG(CFGWalker &Walker);
0399
0400 til::SExpr *lookupStmt(const Stmt *S);
0401
0402 til::BasicBlock *lookupBlock(const CFGBlock *B) {
0403 return BlockMap[B->getBlockID()];
0404 }
0405
0406 const til::SCFG *getCFG() const { return Scfg; }
0407 til::SCFG *getCFG() { return Scfg; }
0408
0409 private:
0410
0411 friend class CFGWalker;
0412
0413 til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
0414 CallingContext *Ctx) ;
0415 til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
0416 til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
0417 til::SExpr *translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE,
0418 CallingContext *Ctx);
0419 til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx,
0420 const Expr *SelfE = nullptr);
0421 til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
0422 CallingContext *Ctx);
0423 til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
0424 CallingContext *Ctx);
0425 til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
0426 CallingContext *Ctx);
0427 til::SExpr *translateBinOp(til::TIL_BinaryOpcode Op,
0428 const BinaryOperator *BO,
0429 CallingContext *Ctx, bool Reverse = false);
0430 til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op,
0431 const BinaryOperator *BO,
0432 CallingContext *Ctx, bool Assign = false);
0433 til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
0434 CallingContext *Ctx);
0435 til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
0436 til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
0437 CallingContext *Ctx);
0438 til::SExpr *translateAbstractConditionalOperator(
0439 const AbstractConditionalOperator *C, CallingContext *Ctx);
0440
0441 til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
0442
0443
0444 using StatementMap = llvm::DenseMap<const Stmt *, til::SExpr *>;
0445
0446
0447 using LVarIndexMap = llvm::DenseMap<const ValueDecl *, unsigned>;
0448
0449
0450 using NameVarPair = std::pair<const ValueDecl *, til::SExpr *>;
0451 using LVarDefinitionMap = CopyOnWriteVector<NameVarPair>;
0452
0453 struct BlockInfo {
0454 LVarDefinitionMap ExitMap;
0455 bool HasBackEdges = false;
0456
0457
0458 unsigned UnprocessedSuccessors = 0;
0459
0460
0461 unsigned ProcessedPredecessors = 0;
0462
0463 BlockInfo() = default;
0464 BlockInfo(BlockInfo &&) = default;
0465 BlockInfo &operator=(BlockInfo &&) = default;
0466 };
0467
0468 void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First);
0469 void enterCFGBlock(const CFGBlock *B);
0470 bool visitPredecessors() { return true; }
0471 void handlePredecessor(const CFGBlock *Pred);
0472 void handlePredecessorBackEdge(const CFGBlock *Pred);
0473 void enterCFGBlockBody(const CFGBlock *B);
0474 void handleStatement(const Stmt *S);
0475 void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD);
0476 void exitCFGBlockBody(const CFGBlock *B);
0477 bool visitSuccessors() { return true; }
0478 void handleSuccessor(const CFGBlock *Succ);
0479 void handleSuccessorBackEdge(const CFGBlock *Succ);
0480 void exitCFGBlock(const CFGBlock *B);
0481 void exitCFG(const CFGBlock *Last);
0482
0483 void insertStmt(const Stmt *S, til::SExpr *E) {
0484 SMap.insert(std::make_pair(S, E));
0485 }
0486
0487 til::SExpr *addStatement(til::SExpr *E, const Stmt *S,
0488 const ValueDecl *VD = nullptr);
0489 til::SExpr *lookupVarDecl(const ValueDecl *VD);
0490 til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
0491 til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
0492
0493 void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
0494 void mergeEntryMap(LVarDefinitionMap Map);
0495 void mergeEntryMapBackEdge();
0496 void mergePhiNodesBackEdge(const CFGBlock *Blk);
0497
0498 private:
0499
0500
0501 static const bool CapabilityExprMode = true;
0502
0503 til::MemRegionRef Arena;
0504
0505
0506 til::Variable *SelfVar = nullptr;
0507
0508 til::SCFG *Scfg = nullptr;
0509
0510
0511 StatementMap SMap;
0512
0513
0514 LVarIndexMap LVarIdxMap;
0515
0516
0517 std::vector<til::BasicBlock *> BlockMap;
0518
0519
0520 std::vector<BlockInfo> BBInfo;
0521
0522 LVarDefinitionMap CurrentLVarMap;
0523 std::vector<til::Phi *> CurrentArguments;
0524 std::vector<til::SExpr *> CurrentInstructions;
0525 std::vector<til::Phi *> IncompleteArgs;
0526 til::BasicBlock *CurrentBB = nullptr;
0527 BlockInfo *CurrentBlockInfo = nullptr;
0528 };
0529
0530 #ifndef NDEBUG
0531
0532 void printSCFG(CFGWalker &Walker);
0533 #endif
0534
0535 }
0536 }
0537
0538 #endif