diff --git a/clang/include/clang/CConv/AVarBoundsInfo.h b/clang/include/clang/CConv/AVarBoundsInfo.h index bb99c45f262e..4e6f847f6400 100644 --- a/clang/include/clang/CConv/AVarBoundsInfo.h +++ b/clang/include/clang/CConv/AVarBoundsInfo.h @@ -97,9 +97,10 @@ class AvarBoundsInference { // Infer bounds for the given key from the set of given ARR atoms. // The flag FromPB requests the inference to use potential length variables. - bool inferBounds(BoundsKey K, bool FromPB = false); + bool inferBounds(BoundsKey K, AVarGraph &BKGraph, bool FromPB = false); private: bool inferPossibleBounds(BoundsKey K, ABounds *SB, + AVarGraph &BKGraph, std::set &EB); bool intersectBounds(std::set &ProgVars, @@ -110,6 +111,7 @@ class AvarBoundsInference { std::set &ResBounds); bool predictBounds(BoundsKey K, std::set &Neighbours, + AVarGraph &BKGraph, ABounds **KB); @@ -120,7 +122,7 @@ class AvarBoundsInference { class AVarBoundsInfo { public: - AVarBoundsInfo() : ProgVarGraph(this) { + AVarBoundsInfo() : ProgVarGraph(this), CtxSensProgVarGraph(this) { BCount = 1; PVarInfo.clear(); InProgramArrPtrBoundsKeys.clear(); @@ -208,7 +210,8 @@ class AVarBoundsInfo { // Create context sensitive BoundsKey variables for the given set of // ConstraintVariables. bool contextualizeCVar(CallExpr *CE, - const std::set &CV); + const std::set &CV, + ASTContext *C); // Get the context sensitive BoundsKey for the given key. // If there exists no context-sensitive bounds key, we just return // the provided key. @@ -269,6 +272,9 @@ class AVarBoundsInfo { // Graph of all program variables. AVarGraph ProgVarGraph; + // Graph that contains only edges between context-sensitive + // BoundsKey and corresponding original BoundsKey. + AVarGraph CtxSensProgVarGraph; // Stats on techniques used to find length for various variables. AVarBoundsStats BoundsInferStats; // This is the map of pointer variable bounds key and set of bounds key @@ -293,6 +299,9 @@ class AVarBoundsInfo { void insertProgramVar(BoundsKey NK, ProgramVar *PV); + void insertCtxSensBoundsKey(ProgramVar *OldPV, BoundsKey NK, + const CtxFunctionArgScope *CFAS); + // Check if the provided bounds key corresponds to function return. bool isFunctionReturn(BoundsKey BK); @@ -303,9 +312,11 @@ class AVarBoundsInfo { // returns true if any thing changed, else false. bool keepHighestPriorityBounds(std::set &ArrPtrs); - // Perform worklist based inference on the requested array variables. + // Perform worklist based inference on the requested array variables using + // the provided graph. // The flag FromPB requests the algorithm to use potential length variables. bool performWorkListInference(std::set &ArrNeededBounds, + AVarGraph &BKGraph, bool FromPB = false); void insertParamKey(ParamDeclType ParamDecl, BoundsKey NK); diff --git a/clang/include/clang/CConv/ConstraintVariables.h b/clang/include/clang/CConv/ConstraintVariables.h index 61c31ef88a57..d3be60ccdaee 100644 --- a/clang/include/clang/CConv/ConstraintVariables.h +++ b/clang/include/clang/CConv/ConstraintVariables.h @@ -173,13 +173,20 @@ enum ConsAction { void constrainConsVarGeq(const std::set &LHS, const std::set &RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info); + ConsAction CA, bool doEqType, + ProgramInfo *Info, + bool HandleBoundsKey = true); void constrainConsVarGeq(ConstraintVariable *LHS, const CVarSet &RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info); -void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, + ConsAction CA, bool doEqType, + ProgramInfo *Info, + bool HandleBoundsKey = true); +void constrainConsVarGeq(ConstraintVariable *LHS, + ConstraintVariable *RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info); + ConsAction CA, bool doEqType, + ProgramInfo *Info, + bool HandleBoundsKey = true); // True if [C] is a PVConstraint that contains at least one Atom (i.e., // it represents a C pointer) diff --git a/clang/include/clang/CConv/PersistentSourceLoc.h b/clang/include/clang/CConv/PersistentSourceLoc.h index e16005cacad4..2a08087b8888 100644 --- a/clang/include/clang/CConv/PersistentSourceLoc.h +++ b/clang/include/clang/CConv/PersistentSourceLoc.h @@ -68,6 +68,9 @@ class PersistentSourceLoc { static PersistentSourceLoc mkPSL(const clang::Stmt *S, clang::ASTContext &Context); + static + PersistentSourceLoc mkPSL(const clang::Expr *E, clang::ASTContext &Context); + private: // Create a PersistentSourceLoc based on absolute file path // from the given SourceRange and SourceLocation. diff --git a/clang/include/clang/CConv/ProgramVar.h b/clang/include/clang/CConv/ProgramVar.h index 838f749f4226..6d6e39f256c4 100644 --- a/clang/include/clang/CConv/ProgramVar.h +++ b/clang/include/clang/CConv/ProgramVar.h @@ -17,6 +17,7 @@ #include #include #include "clang/AST/ASTContext.h" +#include "clang/CConv/PersistentSourceLoc.h" typedef uint32_t BoundsKey; @@ -28,6 +29,8 @@ class ProgramVarScope { FunctionScopeKind, // Function parameter scope. FunctionParamScopeKind, + // Context sensitive argument scope. + CtxFunctionArgScopeKind, // Struct scope. StructScopeKind, // Global scope. @@ -35,10 +38,9 @@ class ProgramVarScope { }; ScopeKind getKind() const { return Kind; } -private: - ScopeKind Kind; protected: ProgramVarScope(ScopeKind K): Kind(K) { } + ScopeKind Kind; public: virtual ~ProgramVarScope() { } @@ -49,6 +51,15 @@ class ProgramVarScope { }; +class PVSComp { +public: + + bool operator()(const ProgramVarScope &Lhs, + const ProgramVarScope &Rhs) const { + return Lhs < Rhs; + } +}; + // Scope for all global variables and program constants. class GlobalScope : public ProgramVarScope { public: @@ -94,7 +105,7 @@ class StructScope : public ProgramVarScope { } bool operator==(const ProgramVarScope &O) const { - if (const StructScope *SS = clang::dyn_cast(&O)) { + if (auto *SS = clang::dyn_cast(&O)) { return SS->StName == StName; } return false; @@ -105,26 +116,36 @@ class StructScope : public ProgramVarScope { } bool operator<(const ProgramVarScope &O) const { - return clang::isa(&O); + if (clang::isa(&O)) { + return true; + } + + if (auto *SS = clang::dyn_cast(&O)) { + if (this->StName != SS->StName) { + return StName < SS->StName; + } + return false; + } + + return false; } std::string getStr() const { return "Struct_" + StName; } - static StructScope *getStructScope(std::string StName); + static const StructScope *getStructScope(std::string StName); private: std::string StName; - static std::map StScopeMap; + static std::set AllStScopes; }; -class FunctionScope; class FunctionParamScope : public ProgramVarScope { public: friend class FunctionScope; - FunctionParamScope(std::string FN, bool IsSt) : + FunctionParamScope(const std::string &FN, bool IsSt) : ProgramVarScope(FunctionParamScopeKind), FName(FN), IsStatic(IsSt) { } @@ -135,7 +156,7 @@ class FunctionParamScope : public ProgramVarScope { } bool operator==(const ProgramVarScope &O) const { - if (const FunctionParamScope *FPS = clang::dyn_cast(&O)) { + if (auto *FPS = clang::dyn_cast(&O)) { return (FPS->FName == FName && FPS->IsStatic == IsStatic); } return false; @@ -146,22 +167,111 @@ class FunctionParamScope : public ProgramVarScope { } bool operator<(const ProgramVarScope &O) const { - return clang::isa(&O); + if (clang::isa(&O) || + clang::isa(&O)) { + return true; + } + + if (auto *FPS = clang::dyn_cast(&O)) { + if (this->FName != FPS->FName) { + return FName < FPS->FName; + } + if (this->IsStatic != FPS->IsStatic) { + return IsStatic < FPS->IsStatic; + } + return false; + } + + return false; } std::string getStr() const { return "FuncParm_" + FName; } - static FunctionParamScope *getFunctionParamScope(std::string FnName, - bool IsSt); + const llvm::StringRef getFName() const { + return this->FName; + } -private: + bool getIsStatic() const { + return IsStatic; + } + + static const FunctionParamScope * + getFunctionParamScope(std::string FnName, bool IsSt); + +protected: std::string FName; bool IsStatic; +private: + static std::set AllFnParamScopes; +}; + +// Context-sensitive arguments scope. +class CtxFunctionArgScope : public FunctionParamScope { +public: + friend class FunctionScope; + CtxFunctionArgScope(const std::string &FN, bool IsSt, + const PersistentSourceLoc &CtxPSL) : + FunctionParamScope(FN, IsSt) { + PSL = CtxPSL; + this->Kind = CtxFunctionArgScopeKind; + } - static std::map, - FunctionParamScope*> FnParmScopeMap; + virtual ~CtxFunctionArgScope() { } + + static bool classof(const ProgramVarScope *S) { + return S->getKind() == CtxFunctionArgScopeKind; + } + + bool operator==(const ProgramVarScope &O) const { + if (auto *FPS = clang::dyn_cast(&O)) { + return (FPS->FName == FName && + FPS->IsStatic == IsStatic && + !(FPS->PSL < PSL || PSL < FPS->PSL)); + } + return false; + } + + bool operator!=(const ProgramVarScope &O) const { + return !(*this == O); + } + + bool operator<(const ProgramVarScope &O) const { + if (clang::isa(&O) || + clang::isa(&O) || + clang::isa(&O)) { + return true; + } + + if (auto *FPS = clang::dyn_cast(&O)) { + if (this->FName != FPS->FName) { + return FName < FPS->FName; + } + if (this->IsStatic != FPS->IsStatic) { + return IsStatic < FPS->IsStatic; + } + if (FPS->PSL < PSL || PSL < FPS->PSL) { + return PSL < FPS->PSL; + } + return false; + } + + return false; + } + + std::string getStr() const { + return "CtxFuncArg_" + FName; + } + + static const CtxFunctionArgScope * + getCtxFunctionParamScope(const FunctionParamScope *FPS, + const PersistentSourceLoc &PSL); + +private: + PersistentSourceLoc PSL; + + static std::set AllCtxFnArgScopes; }; class FunctionScope : public ProgramVarScope { @@ -177,10 +287,10 @@ class FunctionScope : public ProgramVarScope { } bool operator==(const ProgramVarScope &O) const { - if (const FunctionScope *FS = clang::dyn_cast(&O)) { + if (auto *FS = clang::dyn_cast(&O)) { return (FS->FName == FName && FS->IsStatic == IsStatic); } - if (const FunctionParamScope *FPS = clang::dyn_cast(&O)) { + if (auto *FPS = clang::dyn_cast(&O)) { return (FPS->FName == FName && FPS->IsStatic == IsStatic); } return false; @@ -191,32 +301,53 @@ class FunctionScope : public ProgramVarScope { } bool operator<(const ProgramVarScope &O) const { - return clang::isa(&O); + if (clang::isa(&O) || + clang::isa(&O) || + clang::isa(&O) || + clang::isa(&O)) { + return true; + } + + if (auto *FS = clang::dyn_cast(&O)) { + if (this->FName != FS->FName) { + return FName < FS->FName; + } + if (this->IsStatic != FS->IsStatic) { + return IsStatic < FS->IsStatic; + } + return false; + } + return false; } std::string getStr() const { return "InFunc_" + FName; } - static FunctionScope *getFunctionScope(std::string FnName, bool IsSt); + static const FunctionScope *getFunctionScope(std::string FnName, + bool IsSt); private: std::string FName; bool IsStatic; - static std::map, FunctionScope*> FnScopeMap; + static std::set AllFnScopes; }; // Class that represents a program variable along with its scope. class ProgramVar { public: - ProgramVar(BoundsKey VK, std::string VName, ProgramVarScope *PVS, bool IsCons) : + ProgramVar(BoundsKey VK, std::string VName, + const ProgramVarScope *PVS, + bool IsCons) : K(VK), VarName(VName), VScope(PVS), IsConstant(IsCons) { } - ProgramVar(BoundsKey VK, std::string VName, ProgramVarScope *PVS) : + ProgramVar(BoundsKey VK, std::string VName, + const ProgramVarScope *PVS) : ProgramVar(VK, VName, PVS, false) { } - ProgramVarScope *getScope() { return VScope; } + const ProgramVarScope *getScope() { return VScope; } + void setScope(const ProgramVarScope *PVS) { this->VScope = PVS; } BoundsKey getKey() { return K; } bool IsNumConstant() { return IsConstant; } std::string mkString(bool GetKey = false); @@ -227,7 +358,7 @@ class ProgramVar { private: BoundsKey K; std::string VarName; - ProgramVarScope *VScope; + const ProgramVarScope *VScope; bool IsConstant; }; diff --git a/clang/include/clang/CConv/RewriteUtils.h b/clang/include/clang/CConv/RewriteUtils.h index a1ee8aa90f0b..85f896e6e1dd 100644 --- a/clang/include/clang/CConv/RewriteUtils.h +++ b/clang/include/clang/CConv/RewriteUtils.h @@ -206,6 +206,8 @@ class ArrayBoundsRewriter { ArrayBoundsRewriter(ASTContext *C, ProgramInfo &I): Context(C), Info(I) {} // Get the string representation of the bounds for the given variable. std::string getBoundsString(PVConstraint *PV, Decl *D, bool Isitype = false); + // Check if the constraint variable has newly created bounds string. + bool hasNewBoundsString(PVConstraint *PV, Decl *D, bool Isitype = false); private: ASTContext *Context; ProgramInfo &Info; diff --git a/clang/lib/CConv/AVarBoundsInfo.cpp b/clang/lib/CConv/AVarBoundsInfo.cpp index 57f36910393b..2aa18423968e 100644 --- a/clang/lib/CConv/AVarBoundsInfo.cpp +++ b/clang/lib/CConv/AVarBoundsInfo.cpp @@ -221,7 +221,7 @@ BoundsKey AVarBoundsInfo::getVariable(clang::VarDecl *VD) { if (!hasVarKey(PSL)) { BoundsKey NK = ++BCount; insertVarKey(PSL, NK); - ProgramVarScope *PVS = nullptr; + const ProgramVarScope *PVS = nullptr; if (VD->hasGlobalStorage()) { PVS = GlobalScope::getGlobalScope(); } else { @@ -251,8 +251,8 @@ BoundsKey AVarBoundsInfo::getVariable(clang::ParmVarDecl *PVD) { FD->isStatic(), ParamIdx); if (ParamDeclVarMap.left().find(ParamKey) == ParamDeclVarMap.left().end()) { BoundsKey NK = ++BCount; - FunctionParamScope *FPS = - FunctionParamScope::getFunctionParamScope(FD->getNameAsString(), + const FunctionParamScope *FPS = + FunctionParamScope::getFunctionParamScope(FD->getNameAsString(), FD->isStatic()); std::string ParamName = PVD->getNameAsString(); // If this is a parameter without name!? @@ -277,8 +277,8 @@ BoundsKey AVarBoundsInfo::getVariable(clang::FunctionDecl *FD) { FD->isStatic()); if (FuncDeclVarMap.left().find(FuncKey) == FuncDeclVarMap.left().end()) { BoundsKey NK = ++BCount; - FunctionParamScope *FPS = - FunctionParamScope::getFunctionParamScope(FD->getNameAsString(), + const FunctionParamScope *FPS = + FunctionParamScope::getFunctionParamScope(FD->getNameAsString(), FD->isStatic()); auto *PVar = new ProgramVar(NK, FD->getNameAsString(), FPS); @@ -297,7 +297,7 @@ BoundsKey AVarBoundsInfo::getVariable(clang::FieldDecl *FD) { BoundsKey NK = ++BCount; insertVarKey(PSL, NK); std::string StName = FD->getParent()->getNameAsString(); - StructScope *SS = StructScope::getStructScope(StName); + const StructScope *SS = StructScope::getStructScope(StName); auto *PVar = new ProgramVar(NK, FD->getNameAsString(), SS); insertProgramVar(NK, PVar); if (FD->getType()->isPointerType()) @@ -563,11 +563,11 @@ bool isInSrcArray(ConstraintVariable *CK, Constraints &CS) { // This class picks variables that are in the same scope as the provided scope. class ScopeVisitor { public: - ScopeVisitor(ProgramVarScope *S, std::set &R, + ScopeVisitor(const ProgramVarScope *S, std::set &R, std::map &VarM, std::set &P): TS(S), Res(R), VM(VarM) , PtrAtoms(P) { } - void vistBoundsKey(BoundsKey V) const { + void visitBoundsKey(BoundsKey V) const { // If the variable is non-pointer? if (VM.find(V) != VM.end() && PtrAtoms.find(V) == PtrAtoms.end()) { auto *S = VM[V]; @@ -591,7 +591,7 @@ class ScopeVisitor { } } } - ProgramVarScope *TS; + const ProgramVarScope *TS; std::set &Res; std::map &VM; std::set &PtrAtoms; @@ -669,10 +669,10 @@ AvarBoundsInference:: } bool AvarBoundsInference::inferPossibleBounds(BoundsKey K, ABounds *SB, + AVarGraph &BKGraph, std::set &EB) { bool RetVal = false; if (SB != nullptr) { - auto &VarG = BI->ProgVarGraph; auto *Kvar = BI->getProgramVar(K); bool ValidB = false; auto BKind = SB->getKind(); @@ -697,11 +697,15 @@ bool AvarBoundsInference::inferPossibleBounds(BoundsKey K, ABounds *SB, // bounds variable. ScopeVisitor TV(Kvar->getScope(), PotentialB, BI->PVarInfo, BI->PointerBoundsKey); - VarG.visitBreadthFirst(SBKey, [&TV](BoundsKey BK) { - TV.vistBoundsKey(BK); + BKGraph.visitBreadthFirst(SBKey, [&TV](BoundsKey BK) { + TV.visitBoundsKey(BK); }); } + if (*Kvar->getScope() == *SBVar->getScope()) { + PotentialB.insert(SBVar); + } + mergeReachableProgramVars(PotentialB); // Are there are other in-scope variables where the bounds variable @@ -734,6 +738,7 @@ bool AvarBoundsInference::getRelevantBounds(std::set &RBKeys, bool AvarBoundsInference::predictBounds(BoundsKey K, std::set &Neighbours, + AVarGraph &BKGraph, ABounds **KB) { std::set ResBounds; std::set KBounds; @@ -757,7 +762,7 @@ bool AvarBoundsInference::predictBounds(BoundsKey K, // For function returns we should have atleast one common bound // from all the return values. - if (!inferPossibleBounds(K, B, KBounds) && IsFuncRet) { + if (!inferPossibleBounds(K, B, BKGraph, KBounds) && IsFuncRet) { IsValid = false; break; } @@ -777,7 +782,7 @@ bool AvarBoundsInference::predictBounds(BoundsKey K, } return IsValid; } -bool AvarBoundsInference::inferBounds(BoundsKey K, bool FromPB) { +bool AvarBoundsInference::inferBounds(BoundsKey K, AVarGraph &BKGraph, bool FromPB) { bool IsChanged = false; if (BI->InvalidBounds.find(K) == BI->InvalidBounds.end()) { @@ -786,7 +791,6 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, bool FromPB) { if (FromPB) { auto &PotBDs = BI->PotentialCntBounds; if (PotBDs.find(K) != PotBDs.end()) { - auto &VarG = BI->ProgVarGraph; ProgramVar *Kvar = BI->getProgramVar(K); std::set PotentialB; PotentialB.clear(); @@ -799,8 +803,8 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, bool FromPB) { // bounds variable. ScopeVisitor TV(Kvar->getScope(), PotentialB, BI->PVarInfo, BI->PointerBoundsKey); - VarG.visitBreadthFirst(TK, [&TV](BoundsKey BK) { - TV.vistBoundsKey(BK); + BKGraph.visitBreadthFirst(TK, [&TV](BoundsKey BK) { + TV.visitBoundsKey(BK); }); } else { PotentialB.insert(TKVar); @@ -817,8 +821,8 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, bool FromPB) { // Infer from the flow-graph. std::set TmpBkeys; // Try to predict bounds from predecessors. - BI->ProgVarGraph.getPredecessors(K, TmpBkeys); - if (!predictBounds(K, TmpBkeys, &KB)) { + BKGraph.getPredecessors(K, TmpBkeys); + if (!predictBounds(K, TmpBkeys, BKGraph, &KB)) { KB = nullptr; } } @@ -832,6 +836,7 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, bool FromPB) { } bool AVarBoundsInfo::performWorkListInference(std::set &ArrNeededBounds, + AVarGraph &BKGraph, bool FromPB) { bool RetVal = false; std::set WorkList; @@ -848,7 +853,7 @@ bool AVarBoundsInfo::performWorkListInference(std::set &ArrNeededBoun // Remove the bounds key from the worklist. WorkList.erase(CurrArrKey); // Can we find bounds for this Arr? - if (BI.inferBounds(CurrArrKey, FromPB)) { + if (BI.inferBounds(CurrArrKey, BKGraph, FromPB)) { // Record the stats. BoundsInferStats.DataflowMatch.insert(CurrArrKey); // We found the bounds. @@ -856,7 +861,7 @@ bool AVarBoundsInfo::performWorkListInference(std::set &ArrNeededBoun RetVal = true; Changed = true; // Get all the successors of the ARR whose bounds we just found. - ProgVarGraph.getSuccessors(CurrArrKey, NextIterArrs); + BKGraph.getSuccessors(CurrArrKey, NextIterArrs); } } if (Changed) { @@ -866,20 +871,30 @@ bool AVarBoundsInfo::performWorkListInference(std::set &ArrNeededBoun return RetVal; } +void +AVarBoundsInfo::insertCtxSensBoundsKey(ProgramVar *OldPV, + BoundsKey NK, + const CtxFunctionArgScope *CFAS) { + ProgramVar *NKVar = OldPV->makeCopy(NK); + NKVar->setScope(CFAS); + insertProgramVar(NK, NKVar); + ProgVarGraph.addEdge(OldPV->getKey(), NKVar->getKey()); + CtxSensProgVarGraph.addEdge(NKVar->getKey(), OldPV->getKey()); +} + // Here, we create a new BoundsKey for every BoundsKey var that is related to // any ConstraintVariable in CSet and store the information by the // corresponding call expression (CE). -// Here, we only care about variables that have bounds declaration -// or that are used in a bounds declaration. bool -AVarBoundsInfo::contextualizeCVar(CallExpr *CE, const CVarSet &CSet) { +AVarBoundsInfo::contextualizeCVar(CallExpr *CE, const CVarSet &CSet, + ASTContext *C) { for (auto *CV : CSet) { // If this is a FV Constraint the contextualize its returns and // parameters. if (FVConstraint *FV = dyn_cast_or_null(CV)) { - contextualizeCVar(CE, {FV->getReturnVar()}); + contextualizeCVar(CE, {FV->getReturnVar()}, C); for (unsigned i = 0; i < FV->numParams(); i++) { - contextualizeCVar(CE, {FV->getParamVar(i)}); + contextualizeCVar(CE, {FV->getParamVar(i)}, C); } } @@ -887,20 +902,20 @@ AVarBoundsInfo::contextualizeCVar(CallExpr *CE, const CVarSet &CSet) { if (PV->hasBoundsKey()) { // First duplicate the bounds key. BoundsKey CK = PV->getBoundsKey(); - // Either this is a regular variable and used in a bounds declaration - // or a pointer that has bounds declaration? Then we need to - // contextualize it. - // If this is just a regular pointer or variable without declared - // bounds. We ignore it. - if((PV->getCvars().empty() && !ABounds::isKeyUsedInBounds(CK)) || - !PV->hasBoundsStr()) - continue; - + PersistentSourceLoc CEPSL = PersistentSourceLoc::mkPSL(CE, *C); ProgramVar *CKVar = getProgramVar(CK); + + // Create a context sensitive scope. + const CtxFunctionArgScope *CFAS = nullptr; + if (auto *FPS = + dyn_cast_or_null(CKVar->getScope())) { + CFAS = CtxFunctionArgScope::getCtxFunctionParamScope(FPS, CEPSL); + } + auto &BKeyMap = CSBoundsKey[CE]; if (BKeyMap.find(CK) == BKeyMap.end()) { BoundsKey NK = ++BCount; - insertProgramVar(NK, CKVar->makeCopy(NK)); + insertCtxSensBoundsKey(CKVar, NK, CFAS); BKeyMap[CK] = NK; // Next duplicate the Bounds information. BoundsPriority TP = Invalid; @@ -911,7 +926,7 @@ AVarBoundsInfo::contextualizeCVar(CallExpr *CE, const CVarSet &CSet) { if (BKeyMap.find(NBK) == BKeyMap.end()) { BoundsKey TmpBK = ++BCount; BKeyMap[NBK] = TmpBK; - insertProgramVar(TmpBK, NBKVar->makeCopy(TmpBK)); + insertCtxSensBoundsKey(NBKVar, TmpBK, CFAS); } CKBounds = CKBounds->makeCopy(BKeyMap[NBK]); replaceBounds(NK, TP, CKBounds); @@ -1009,6 +1024,34 @@ void AVarBoundsInfo::computerArrPointers(ProgramInfo *PI, continue; } } + + // Get all context-sensitive BoundsKey for each of the actual BKs + // and consider them to be array pointers as well. + // Since context-sensitive BoundsKey will be immediate children + // of the regular bounds key, we just get the neighbours (predecessors + // and successors) of the regular bounds key to get the context-sensitive + // counterparts. + std::set CtxSensBKeys; + CtxSensBKeys.clear(); + std::set TmpBKeys, TmpBKeysF; + for (auto BK : ArrPointers) { + TmpBKeys.clear(); + ProgVarGraph.getPredecessors(BK, TmpBKeys); + TmpBKeysF.insert(TmpBKeys.begin(), TmpBKeys.end()); + TmpBKeys.clear(); + ProgVarGraph.getSuccessors(BK, TmpBKeys); + TmpBKeysF.insert(TmpBKeys.begin(), TmpBKeys.end()); + for (auto TBK : TmpBKeysF) { + ProgramVar *TmpPVar = getProgramVar(TBK); + if (TmpPVar != nullptr) { + if (isa(TmpPVar->getScope())) { + CtxSensBKeys.insert(TBK); + } + } + } + } + + ArrPointers.insert(CtxSensBKeys.begin(), CtxSensBKeys.end()); } bool AVarBoundsInfo::performFlowAnalysis(ProgramInfo *PI) { @@ -1053,9 +1096,12 @@ bool AVarBoundsInfo::performFlowAnalysis(ProgramInfo *PI) { while (Changed) { Changed = false; // Use flow-graph. - Changed = performWorkListInference(ArrNeededBounds) || Changed; + Changed = performWorkListInference(ArrNeededBounds, this->ProgVarGraph) || Changed; // Use potential length variables. - Changed = performWorkListInference(ArrNeededBounds, true) || Changed; + Changed = performWorkListInference(ArrNeededBounds, this->ProgVarGraph, true) || Changed; + // Try solving using context-sensitive BoundsKey. + Changed = performWorkListInference(ArrNeededBounds, this->CtxSensProgVarGraph) || Changed; + Changed = performWorkListInference(ArrNeededBounds, this->CtxSensProgVarGraph, true) || Changed; } return RetVal; @@ -1137,7 +1183,8 @@ bool ContextSensitiveBoundsKeyVisitor::VisitCallExpr(CallExpr *CE) { // Contextualize the function at this call-site. CVarOption COpt = Info.getVariable(FD, Context); if (COpt.hasValue()) - Info.getABoundsInfo().contextualizeCVar(CE, {&COpt.getValue()}); + Info.getABoundsInfo().contextualizeCVar(CE, {&COpt.getValue()}, Context); + } return true; } \ No newline at end of file diff --git a/clang/lib/CConv/ArrayBoundsInferenceConsumer.cpp b/clang/lib/CConv/ArrayBoundsInferenceConsumer.cpp index 6498c9bfa64d..a4ce38f7bf2b 100644 --- a/clang/lib/CConv/ArrayBoundsInferenceConsumer.cpp +++ b/clang/lib/CConv/ArrayBoundsInferenceConsumer.cpp @@ -851,6 +851,13 @@ void LengthVarInference::VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { "to any basic block"); // First, get the BoundsKey for the base. Expr *BE = ASE->getBase()->IgnoreParenCasts(); + + // If this is a multi-level array dereference i.e., a[i][j], + // then try-processing the base ASE i.e., a[i]. + if (ArraySubscriptExpr *SubASE = dyn_cast_or_null(BE)) { + VisitArraySubscriptExpr(SubASE); + return; + } auto BaseCVars = CR->getExprConstraintVars(BE); // Next get the index used. Expr *IdxExpr = ASE->getIdx()->IgnoreParenCasts(); diff --git a/clang/lib/CConv/ConstraintBuilder.cpp b/clang/lib/CConv/ConstraintBuilder.cpp index 6c21d1b46e4a..96b09c697d7f 100644 --- a/clang/lib/CConv/ConstraintBuilder.cpp +++ b/clang/lib/CConv/ConstraintBuilder.cpp @@ -238,8 +238,10 @@ class FunctionVisitor : public RecursiveASTVisitor { } else if (i < TargetFV->numParams()) { // constrain the arg CV to the param CV ConstraintVariable *ParameterDC = TargetFV->getParamVar(i); + // Do not handle bounds key here because we will be + // doing context-sensitive assignment next. constrainConsVarGeq(ParameterDC, ArgumentConstraints, CS, &PL, - Wild_to_Safe, false, &Info); + Wild_to_Safe, false, &Info, false); if (AllTypes && TFD != nullptr) { auto *PVD = TFD->getParamDecl(i); diff --git a/clang/lib/CConv/ConstraintVariables.cpp b/clang/lib/CConv/ConstraintVariables.cpp index 5b6364cceb9e..9210c399e746 100644 --- a/clang/lib/CConv/ConstraintVariables.cpp +++ b/clang/lib/CConv/ConstraintVariables.cpp @@ -1396,7 +1396,8 @@ static void createAtomGeq(Constraints &CS, Atom *L, Atom *R, std::string &Rsn, // If doEqType is true, then also do CA |- LHS <: RHS. void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info) { + ConsAction CA, bool doEqType, ProgramInfo *Info, + bool HandleBoundsKey) { // If one of the constraint is NULL, make the other constraint WILD. // This can happen when a non-function pointer gets assigned to @@ -1425,7 +1426,7 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, // Constrain the return values covariantly. // FIXME: Make neg(CA) here? Function pointers equated constrainConsVarGeq(FCLHS->getReturnVar(), FCRHS->getReturnVar(), CS, - PL, Same_to_Same, doEqType, Info); + PL, Same_to_Same, doEqType, Info, HandleBoundsKey); // Constrain the parameters contravariantly. if (FCLHS->numParams() == FCRHS->numParams()) { @@ -1434,7 +1435,7 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, ConstraintVariable *RHSV = FCRHS->getParamVar(i); // FIXME: Make neg(CA) here? Now: Function pointers equated constrainConsVarGeq(RHSV, LHSV, CS, PL, Same_to_Same, doEqType, - Info); + Info, HandleBoundsKey); } } else { // Constrain both to be top. @@ -1451,7 +1452,7 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, if (PVConstraint *PCRHS = dyn_cast(RHS)) { // Add assignment to bounds info graph. - if (PCLHS->hasBoundsKey() && PCRHS->hasBoundsKey()) { + if (HandleBoundsKey && PCLHS->hasBoundsKey() && PCRHS->hasBoundsKey()) { Info->getABoundsInfo().addAssignment(PCLHS->getBoundsKey(), PCRHS->getBoundsKey()); } @@ -1496,7 +1497,7 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, } // Equate the corresponding FunctionConstraint. constrainConsVarGeq(PCLHS->getFV(), PCRHS->getFV(), CS, PL, CA, - doEqType, Info); + doEqType, Info, HandleBoundsKey); } } else llvm_unreachable("impossible"); @@ -1509,7 +1510,7 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, FVConstraint *FCRHS = dyn_cast(RHS); if (PCLHS && FCRHS) { if (FVConstraint *FCLHS = PCLHS->getFV()) { - constrainConsVarGeq(FCLHS, FCRHS, CS, PL, CA, doEqType, Info); + constrainConsVarGeq(FCLHS, FCRHS, CS, PL, CA, doEqType, Info, HandleBoundsKey); } else { std::string Rsn = "Function:" + FCRHS->getName() + " assigned to non-function pointer."; @@ -1528,17 +1529,19 @@ void constrainConsVarGeq(ConstraintVariable *LHS, ConstraintVariable *RHS, void constrainConsVarGeq(ConstraintVariable *LHS, const CVarSet &RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info) { + ConsAction CA, bool doEqType, ProgramInfo *Info, + bool HandleBoundsKey) { for (const auto &J : RHS) - constrainConsVarGeq(LHS, J, CS, PL, CA, doEqType, Info); + constrainConsVarGeq(LHS, J, CS, PL, CA, doEqType, Info, HandleBoundsKey); } // Given an RHS and a LHS, constrain them to be equal. void constrainConsVarGeq(const CVarSet &LHS, const CVarSet &RHS, Constraints &CS, PersistentSourceLoc *PL, - ConsAction CA, bool doEqType, ProgramInfo *Info) { + ConsAction CA, bool doEqType, ProgramInfo *Info, + bool HandleBoundsKey) { for (const auto &I : LHS) - constrainConsVarGeq(I, RHS, CS, PL, CA, doEqType, Info); + constrainConsVarGeq(I, RHS, CS, PL, CA, doEqType, Info, HandleBoundsKey); } // True if [C] is a PVConstraint that contains at least one Atom (i.e., diff --git a/clang/lib/CConv/DeclRewriter.cpp b/clang/lib/CConv/DeclRewriter.cpp index 1c0674e97266..05f4d89a40b7 100644 --- a/clang/lib/CConv/DeclRewriter.cpp +++ b/clang/lib/CConv/DeclRewriter.cpp @@ -568,6 +568,11 @@ bool FunctionDeclBuilder::VisitFunctionDecl(FunctionDecl *FD) { if (DidAnyReturn) NewSig = getStorageQualifierString(Definition) + ReturnVar; + // We need to rewrite params if there is a bounds strings for + // the return too. + DidAnyParams = DidAnyParams || + ABRewriter.hasNewBoundsString(Defn, FD, GeneratedRetIType); + if (DidAnyReturn && DidAnyParams) NewSig += Defnc->getName(); diff --git a/clang/lib/CConv/PersistentSourceLoc.cpp b/clang/lib/CConv/PersistentSourceLoc.cpp index 8f1caf11f64b..8293f9335c61 100644 --- a/clang/lib/CConv/PersistentSourceLoc.cpp +++ b/clang/lib/CConv/PersistentSourceLoc.cpp @@ -32,6 +32,12 @@ PersistentSourceLoc::mkPSL(const Stmt *S, ASTContext &Context) { return mkPSL(S->getSourceRange(), S->getBeginLoc(), Context); } +// Create a PersistentSourceLoc for an Expression. +PersistentSourceLoc +PersistentSourceLoc::mkPSL(const clang::Expr *E, clang::ASTContext &Context) { + return mkPSL(E->getSourceRange(), E->getBeginLoc(), Context); +} + // Use the PresumedLoc infrastructure to get a file name and expansion // line and column numbers for a SourceLocation. PersistentSourceLoc diff --git a/clang/lib/CConv/ProgramVar.cpp b/clang/lib/CConv/ProgramVar.cpp index 8a23584cc240..1a733c8eb1d9 100644 --- a/clang/lib/CConv/ProgramVar.cpp +++ b/clang/lib/CConv/ProgramVar.cpp @@ -13,11 +13,12 @@ #include "clang/CConv/ProgramVar.h" GlobalScope *GlobalScope::ProgScope = nullptr; -std::map StructScope::StScopeMap; -std::map, FunctionScope*> - FunctionScope::FnScopeMap; -std::map, FunctionParamScope*> - FunctionParamScope::FnParmScopeMap; +std::set StructScope::AllStScopes; +std::set + FunctionParamScope::AllFnParamScopes; +std::set FunctionScope::AllFnScopes; +std::set + CtxFunctionArgScope::AllCtxFnArgScopes; GlobalScope *GlobalScope::getGlobalScope() { if (ProgScope == nullptr) { @@ -26,28 +27,39 @@ GlobalScope *GlobalScope::getGlobalScope() { return ProgScope; } -StructScope *StructScope::getStructScope(std::string StName) { - if (StScopeMap.find(StName) == StScopeMap.end()) { - StScopeMap[StName] = new StructScope(StName); +const StructScope *StructScope::getStructScope(std::string StName) { + StructScope TmpS(StName); + if (AllStScopes.find(TmpS) == AllStScopes.end()) { + AllStScopes.insert(TmpS); } - return StScopeMap[StName]; + return &(*AllStScopes.find(TmpS)); } -FunctionParamScope *FunctionParamScope::getFunctionParamScope( +const FunctionParamScope *FunctionParamScope::getFunctionParamScope( std::string FnName, bool IsSt) { - auto MapK = std::make_pair(FnName, IsSt); - if (FnParmScopeMap.find(MapK) == FnParmScopeMap.end()) { - FnParmScopeMap[MapK] = new FunctionParamScope(FnName, IsSt); + FunctionParamScope TmpFPS(FnName, IsSt); + if (AllFnParamScopes.find(TmpFPS) == AllFnParamScopes.end()) { + AllFnParamScopes.insert(TmpFPS); } - return FnParmScopeMap[MapK]; + return &(*AllFnParamScopes.find(TmpFPS)); } -FunctionScope *FunctionScope::getFunctionScope(std::string FnName, bool IsSt) { - auto MapK = std::make_pair(FnName, IsSt); - if (FnScopeMap.find(MapK) == FnScopeMap.end()) { - FnScopeMap[MapK] = new FunctionScope(FnName, IsSt); +const CtxFunctionArgScope *CtxFunctionArgScope::getCtxFunctionParamScope( + const FunctionParamScope *FPS, const PersistentSourceLoc &PSL) { + CtxFunctionArgScope TmpAS(FPS->getFName(), FPS->getIsStatic(), PSL); + if (AllCtxFnArgScopes.find(TmpAS) == AllCtxFnArgScopes.end()) { + AllCtxFnArgScopes.insert(TmpAS); } - return FnScopeMap[MapK]; + return &(*AllCtxFnArgScopes.find(TmpAS)); +} + +const FunctionScope *FunctionScope::getFunctionScope(std::string FnName, + bool IsSt) { + FunctionScope TmpFS(FnName, IsSt); + if (AllFnScopes.find(TmpFS) == AllFnScopes.end()) { + AllFnScopes.insert(TmpFS); + } + return &(*AllFnScopes.find(TmpFS)); } diff --git a/clang/lib/CConv/RewriteUtils.cpp b/clang/lib/CConv/RewriteUtils.cpp index bb78f0b5d359..a4b56ef483f1 100644 --- a/clang/lib/CConv/RewriteUtils.cpp +++ b/clang/lib/CConv/RewriteUtils.cpp @@ -366,6 +366,13 @@ std::string ArrayBoundsRewriter::getBoundsString(PVConstraint *PV, return BString; } +bool ArrayBoundsRewriter::hasNewBoundsString(PVConstraint *PV, Decl *D, + bool Isitype) { + std::string BStr = getBoundsString(PV, D, Isitype); + // There is a bounds string but has nothing declared? + return !BStr.empty() && !PV->hasBoundsStr(); +} + std::set RewriteConsumer::EmittedDiagnostics; void RewriteConsumer::emitRootCauseDiagnostics(ASTContext &Context) { clang::DiagnosticsEngine &DE = Context.getDiagnostics(); diff --git a/clang/test/CheckedCRewriter/3d-allocation.c b/clang/test/CheckedCRewriter/3d-allocation.c index c94a7f2615ab..fad37cb391ca 100644 --- a/clang/test/CheckedCRewriter/3d-allocation.c +++ b/clang/test/CheckedCRewriter/3d-allocation.c @@ -12,7 +12,7 @@ extern _Itype_for_any(T) void *malloc(size_t size) : itype(_Array_ptr) byte_c int ***malloc3d(int y, int x, int z) { //CHECK_NOALL: int ***malloc3d(int y, int x, int z) { - //CHECK_ALL: _Array_ptr<_Array_ptr<_Array_ptr>> malloc3d(int y, int x, int z) { + //CHECK_ALL: _Array_ptr<_Array_ptr<_Array_ptr>> malloc3d(int y, int x, int z) : count(y) { int i, j; @@ -63,7 +63,7 @@ int main(void) { int ***t2 = malloc3d(y, x, z); //CHECK_NOALL: int ***t2 = malloc3d(y, x, z); - //CHECK_ALL: _Array_ptr<_Array_ptr<_Array_ptr>> t2 = malloc3d(y, x, z); + //CHECK_ALL: _Array_ptr<_Array_ptr<_Array_ptr>> t2 : count(y) = malloc3d(y, x, z); for (i = 0; i < y; ++i) { diff --git a/clang/test/CheckedCRewriter/contextsensitivebounds1.c b/clang/test/CheckedCRewriter/contextsensitivebounds1.c new file mode 100644 index 000000000000..305221f20882 --- /dev/null +++ b/clang/test/CheckedCRewriter/contextsensitivebounds1.c @@ -0,0 +1,64 @@ +/** +Test for context sensitive bounds for internal functions. +**/ + +// RUN: cconv-standalone -alltypes %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_ALL","CHECK" %s +// RUN: cconv-standalone %s -- | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s +_Itype_for_any(T) void *somefunc(unsigned long size) : itype(_Array_ptr) byte_count(size); +struct hash_node +{ + int *p_key; + int *q_key; + int *r_key; + int *w_key; + int *y_key; + unsigned pqlen; + unsigned r_len; + unsigned xo; + unsigned lo; +}; + +//CHECK_ALL: _Array_ptr p_key : byte_count(pqlen); +//CHECK_NOALL: int *p_key; +//CHECK_ALL: _Array_ptr q_key : byte_count(pqlen); +//CHECK_NOALL: int *q_key; +//CHECK_ALL: _Array_ptr r_key : byte_count(r_len); +//CHECK_NOALL: int *r_key; +//CHECK_ALL: _Array_ptr w_key : count(xo); +//CHECK_NOALL: int *w_key; +//CHECK_ALL: _Array_ptr y_key : count(lo); +//CHECK_NOALL: int *y_key; + +int bar(struct hash_node *p) { + p->p_key = p->q_key; + return 0; +} +//CHECK_ALL: int bar(_Ptr p) { +//CHECK_NOALL: int bar(_Ptr p) { + + +void ctxsensfunc(int *p, unsigned n) { + unsigned i; + for (i=0; i p : count(n), unsigned n) { +//CHECK_NOALL: void ctxsensfunc(int *p, unsigned n) { + +int foo() { + unsigned i,j; + struct hash_node *n = somefunc(sizeof(struct hash_node)); + i = 5*sizeof(int); + n->pqlen = i; + n->p_key = somefunc(i); + n->r_key = somefunc(n->r_len); + ctxsensfunc(n->w_key, n->xo); + n->p_key[0] = 1; + n->r_key[0] = 1; + j = n->lo; + ctxsensfunc(n->y_key, j); + return 0; +} +//CHECK_ALL: _Ptr n = somefunc(sizeof(struct hash_node)); +//CHECK_NOALL: struct hash_node *n = somefunc(sizeof(struct hash_node));