Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:23

0001 //===- ThreadSafetyCommon.h -------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Parts of thread safety analysis that are not specific to thread safety
0010 // itself have been factored into classes here, where they can be potentially
0011 // used by other analyses.  Currently these include:
0012 //
0013 // * Generalize clang CFG visitors.
0014 // * Conversion of the clang CFG to SSA form.
0015 // * Translation of clang Exprs to TIL SExprs
0016 //
0017 // UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
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 // Various helper functions on til::SExpr
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   // We treat a top-level wildcard as the "univsersal" lock.
0071   // It matches everything for the purpose of checking locks, but not
0072   // for unlocking them.
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 }  // namespace sx
0098 
0099 // This class defines the interface of a clang CFG Visitor.
0100 // CFGWalker will invoke the following methods.
0101 // Note that methods are not virtual; the visitor is templatized.
0102 class CFGVisitor {
0103   // Enter the CFG for Decl D, and perform any initial setup operations.
0104   void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
0105 
0106   // Enter a CFGBlock.
0107   void enterCFGBlock(const CFGBlock *B) {}
0108 
0109   // Returns true if this visitor implements handlePredecessor
0110   bool visitPredecessors() { return true; }
0111 
0112   // Process a predecessor edge.
0113   void handlePredecessor(const CFGBlock *Pred) {}
0114 
0115   // Process a successor back edge to a previously visited block.
0116   void handlePredecessorBackEdge(const CFGBlock *Pred) {}
0117 
0118   // Called just before processing statements.
0119   void enterCFGBlockBody(const CFGBlock *B) {}
0120 
0121   // Process an ordinary statement.
0122   void handleStatement(const Stmt *S) {}
0123 
0124   // Process a destructor call
0125   void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
0126 
0127   // Called after all statements have been handled.
0128   void exitCFGBlockBody(const CFGBlock *B) {}
0129 
0130   // Return true
0131   bool visitSuccessors() { return true; }
0132 
0133   // Process a successor edge.
0134   void handleSuccessor(const CFGBlock *Succ) {}
0135 
0136   // Process a successor back edge to a previously visited block.
0137   void handleSuccessorBackEdge(const CFGBlock *Succ) {}
0138 
0139   // Leave a CFGBlock.
0140   void exitCFGBlock(const CFGBlock *B) {}
0141 
0142   // Leave the CFG, and perform any final cleanup operations.
0143   void exitCFG(const CFGBlock *Last) {}
0144 };
0145 
0146 // Walks the clang CFG, and invokes methods on a given CFGVisitor.
0147 class CFGWalker {
0148 public:
0149   CFGWalker() = default;
0150 
0151   // Initialize the CFGWalker.  This setup only needs to be done once, even
0152   // if there are multiple passes over the CFG.
0153   bool init(AnalysisDeclContext &AC) {
0154     ACtx = &AC;
0155     CFGraph = AC.getCFG();
0156     if (!CFGraph)
0157       return false;
0158 
0159     // Ignore anonymous functions.
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   // Traverse the CFG, calling methods on V as appropriate.
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       // Process predecessors, handling back edges last
0183       if (V.visitPredecessors()) {
0184         SmallVector<CFGBlock*, 4> BackEdges;
0185         // Process successors
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       // Process statements
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       // Process successors, handling back edges first.
0228       if (V.visitSuccessors()) {
0229         SmallVector<CFGBlock*, 8> ForwardEdges;
0230 
0231         // Process successors
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 // TODO: move this back into ThreadSafety.cpp
0270 // This is specific to thread safety.  It is here because
0271 // translateAttrExpr needs it, but that should be moved too.
0272 class CapabilityExpr {
0273 private:
0274   /// The capability expression and whether it's negated.
0275   llvm::PointerIntPair<const til::SExpr *, 1, bool> CapExpr;
0276 
0277   /// The kind of capability as specified by @ref CapabilityAttr::getName.
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   // Don't allow implicitly-constructed StringRefs since we'll capture them.
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 // Translate clang::Expr to til::SExpr.
0339 class SExprBuilder {
0340 public:
0341   /// Encapsulates the lexical context of a function call.  The lexical
0342   /// context includes the arguments to the call, including the implicit object
0343   /// argument.  When an attribute containing a mutex expression is attached to
0344   /// a method, the expression may refer to formal parameters of the method.
0345   /// Actual arguments must be substituted for formal parameters to derive
0346   /// the appropriate mutex expression in the lexical context where the function
0347   /// is called.  PrevCtx holds the context in which the arguments themselves
0348   /// should be evaluated; multiple calling contexts can be chained together
0349   /// by the lock_returned attribute.
0350   struct CallingContext {
0351     // The previous context; or 0 if none.
0352     CallingContext  *Prev;
0353 
0354     // The decl to which the attr is attached.
0355     const NamedDecl *AttrDecl;
0356 
0357     // Implicit object argument -- e.g. 'this'
0358     llvm::PointerUnion<const Expr *, til::SExpr *> SelfArg = nullptr;
0359 
0360     // Number of funArgs
0361     unsigned NumArgs = 0;
0362 
0363     // Function arguments
0364     llvm::PointerUnion<const Expr *const *, til::SExpr *> FunArgs = nullptr;
0365 
0366     // is Self referred to with -> or .?
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     // FIXME: we don't always have a self-variable.
0375     SelfVar = new (Arena) til::Variable(nullptr);
0376     SelfVar->setKind(til::Variable::VK_SFun);
0377   }
0378 
0379   // Translate a clang expression in an attribute to a til::SExpr.
0380   // Constructs the context from D, DeclExp, and SelfDecl.
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   // Translate a variable reference.
0388   til::LiteralPtr *createVariable(const VarDecl *VD);
0389 
0390   // Create placeholder for this: we don't know the VarDecl on construction yet.
0391   std::pair<til::LiteralPtr *, StringRef>
0392   createThisPlaceholder(const Expr *Exp);
0393 
0394   // Translate a clang statement or expression to a TIL expression.
0395   // Also performs substitution of variables; Ctx provides the context.
0396   // Dispatches on the type of S.
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   // We implement the CFGVisitor API
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   // Map from statements in the clang CFG to SExprs in the til::SCFG.
0444   using StatementMap = llvm::DenseMap<const Stmt *, til::SExpr *>;
0445 
0446   // Map from clang local variables to indices in a LVarDefinitionMap.
0447   using LVarIndexMap = llvm::DenseMap<const ValueDecl *, unsigned>;
0448 
0449   // Map from local variable indices to SSA variables (or constants).
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     // Successors yet to be processed
0458     unsigned UnprocessedSuccessors = 0;
0459 
0460     // Predecessors already processed
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   // Set to true when parsing capability expressions, which get translated
0500   // inaccurately in order to hack around smart pointers etc.
0501   static const bool CapabilityExprMode = true;
0502 
0503   til::MemRegionRef Arena;
0504 
0505   // Variable to use for 'this'.  May be null.
0506   til::Variable *SelfVar = nullptr;
0507 
0508   til::SCFG *Scfg = nullptr;
0509 
0510   // Map from Stmt to TIL Variables
0511   StatementMap SMap;
0512 
0513   // Indices of clang local vars.
0514   LVarIndexMap LVarIdxMap;
0515 
0516   // Map from clang to til BBs.
0517   std::vector<til::BasicBlock *> BlockMap;
0518 
0519   // Extra information per BB. Indexed by clang BlockID.
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 // Dump an SCFG to llvm::errs().
0532 void printSCFG(CFGWalker &Walker);
0533 #endif // NDEBUG
0534 
0535 } // namespace threadSafety
0536 } // namespace clang
0537 
0538 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H