From 22779c356c9d5a642fbe3a9df96c359b5d033d17 Mon Sep 17 00:00:00 2001 From: Aravind Machiry Date: Sun, 30 May 2021 20:33:05 -0400 Subject: [PATCH 1/3] Adding bounds inferrence of the form count(i+1) --- clang/include/clang/3C/ABounds.h | 20 +- clang/include/clang/3C/AVarBoundsInfo.h | 40 ++- clang/lib/3C/ABounds.cpp | 12 + clang/lib/3C/AVarBoundsInfo.cpp | 315 +++++++++++------- clang/lib/3C/ArrayBoundsInferenceConsumer.cpp | 2 + clang/test/3C/allarrays.c | 2 +- clang/test/3C/arrboundsheuristics.c | 2 +- clang/test/3C/arrctxsenbounds.c | 2 +- clang/test/3C/lowerbound.c | 2 +- clang/test/3C/malloc_array.c | 4 +- clang/test/3C/multidef1a.c | 2 +- clang/test/3C/multidef1b.c | 2 +- clang/test/3C/placements.c | 4 +- clang/test/3C/realloc.c | 2 +- clang/test/3C/realloc_complex.c | 4 +- clang/test/3C/refarrsubscript.c | 6 +- clang/test/3C/resolve_itypes.c | 2 +- clang/test/3C/simple_locals.c | 4 +- clang/test/3C/untypedprototypes.c | 6 +- 19 files changed, 289 insertions(+), 144 deletions(-) diff --git a/clang/include/clang/3C/ABounds.h b/clang/include/clang/3C/ABounds.h index b61b52e03fc5..fa49a7f44f3e 100644 --- a/clang/include/clang/3C/ABounds.h +++ b/clang/include/clang/3C/ABounds.h @@ -28,6 +28,8 @@ class ABounds { InvalidKind, // Bounds that represent number of items. CountBoundKind, + // Count bounds but plus one, i.e., count(i+1) + CountPlusOneBoundKind, // Bounds that represent number of bytes. ByteBoundKind, // Bounds that represent range. @@ -35,7 +37,7 @@ class ABounds { }; BoundsKind getKind() const { return Kind; } -private: +protected: BoundsKind Kind; protected: @@ -83,10 +85,24 @@ class CountBound : public ABounds { BoundsKey getCountVar() { return CountVar; } -private: +protected: BoundsKey CountVar; }; +class CountPlusOneBound : public CountBound { +public: + CountPlusOneBound(BoundsKey Var) : CountBound(Var) { + this->Kind = CountPlusOneBoundKind; + } + + std::string mkString(AVarBoundsInfo *ABI, clang::Decl *D = nullptr) override; + bool areSame(ABounds *O, AVarBoundsInfo *ABI) override; + + static bool classof(const ABounds *S) { + return S->getKind() == CountPlusOneBoundKind; + } +}; + class ByteBound : public ABounds { public: ByteBound(BoundsKey Var) : ABounds(ByteBoundKind), ByteVar(Var) { diff --git a/clang/include/clang/3C/AVarBoundsInfo.h b/clang/include/clang/3C/AVarBoundsInfo.h index d685364f6686..95550221856c 100644 --- a/clang/include/clang/3C/AVarBoundsInfo.h +++ b/clang/include/clang/3C/AVarBoundsInfo.h @@ -138,6 +138,8 @@ class AvarBoundsInference { bool hasImpossibleBounds(BoundsKey BK); // Set the given pointer to have impossible bounds. void setImpossibleBounds(BoundsKey BK); + // Infer bounds of the given pointer key from potential bounds. + bool inferFromPotentialBounds(BoundsKey BK, AVarGraph &BKGraph); AVarBoundsInfo *BI; @@ -147,6 +149,31 @@ class AvarBoundsInference { std::set BKsFailedFlowInference; }; +// Class that maintains information about potential bounds for +// various pointer variables. +class PotentialBoundsInfo { +public: + PotentialBoundsInfo() { + PotentialCntBounds.clear(); + PotentialCntPOneBounds.clear(); + } + // Count Bounds, i.e., count(i). + bool hasPotentialCountBounds(BoundsKey PtrBK); + std::set &getPotentialBounds(BoundsKey PtrBK); + void addPotentialBounds(BoundsKey BK, const std::set &PotK); + + // Count Bounds Plus one, i.e., count(i+1). + bool hasPotentialCountPOneBounds(BoundsKey PtrBK); + std::set &getPotentialBoundsPOne(BoundsKey PtrBK); + void addPotentialBoundsPOne(BoundsKey BK, const std::set &PotK); +private: + // This is the map of pointer variable bounds key and set of bounds key + // which can be the count bounds. + std::map> PotentialCntBounds; + // Potential count + 1 bounds. + std::map> PotentialCntPOneBounds; +}; + class AVarBoundsInfo { public: AVarBoundsInfo() : ProgVarGraph(this), CtxSensProgVarGraph(this), @@ -171,7 +198,10 @@ class AVarBoundsInfo { bool replaceBounds(BoundsKey L, BoundsPriority P, ABounds *B); ABounds *getBounds(BoundsKey L, BoundsPriority ReqP = Invalid, BoundsPriority *RetP = nullptr); - bool updatePotentialCountBounds(BoundsKey BK, std::set &CntBK); + bool updatePotentialCountBounds(BoundsKey BK, + const std::set &CntBK); + bool updatePotentialCountPOneBounds(BoundsKey BK, + const std::set &CntBK); // Try and get BoundsKey, into R, for the given declaration. If the // declaration does not have a BoundsKey then return false. @@ -316,9 +346,8 @@ class AVarBoundsInfo { AVarGraph RevCtxSensProgVarGraph; // 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 - // which can be the count bounds. - std::map> PotentialCntBounds; + // Information about potential bounds. + PotentialBoundsInfo PotBoundsInfo; // Context-sensitive bounds key handler CtxSensitiveBoundsKeyHandler CSBKeyHandler; @@ -351,7 +380,8 @@ class AVarBoundsInfo { // Perform worklist based inference on the requested array variables using // the provided graph and potential length variables. bool performWorkListInference(const std::set &ArrNeededBounds, - AVarGraph &BKGraph, AvarBoundsInference &BI); + AVarGraph &BKGraph, AvarBoundsInference &BI, + bool FromPB); void insertParamKey(ParamDeclType ParamDecl, BoundsKey NK); }; diff --git a/clang/lib/3C/ABounds.cpp b/clang/lib/3C/ABounds.cpp index 8ecb216569ba..0e2f06c3988f 100644 --- a/clang/lib/3C/ABounds.cpp +++ b/clang/lib/3C/ABounds.cpp @@ -93,6 +93,18 @@ BoundsKey CountBound::getBKey() { return this->CountVar; } ABounds *CountBound::makeCopy(BoundsKey NK) { return new CountBound(NK); } +std::string CountPlusOneBound::mkString(AVarBoundsInfo *ABI, clang::Decl *D) { + std::string CVar = ABounds::getBoundsKeyStr(CountVar, ABI, D); + return "count(" + CVar + " + 1)"; +} +bool CountPlusOneBound::areSame(ABounds *O, AVarBoundsInfo *ABI) { + if (O != nullptr) { + if (CountPlusOneBound *OT = dyn_cast(O)) + return ABI->areSameProgramVar(this->CountVar, OT->CountVar); + } + return false; +} + std::string ByteBound::mkString(AVarBoundsInfo *ABI, clang::Decl *D) { return "byte_count(" + ABounds::getBoundsKeyStr(ByteVar, ABI, D) + ")"; } diff --git a/clang/lib/3C/AVarBoundsInfo.cpp b/clang/lib/3C/AVarBoundsInfo.cpp index 2b7d209c63fe..d2a63726dd76 100644 --- a/clang/lib/3C/AVarBoundsInfo.cpp +++ b/clang/lib/3C/AVarBoundsInfo.cpp @@ -132,6 +132,25 @@ mergeReachableProgramVars(BoundsKey TarBK, std::set &AllVars) { ProgramVar *BVar = nullptr; bool IsTarNTArr = BI->NtArrPointerBoundsKey.find(TarBK) != BI->NtArrPointerBoundsKey.end(); + // First, find all variables that are in the SAME scope as TarBK. + // If there is only one? Then use it. + std::set SameScopeVars; + ProgramVar *TarBVar = BI->getProgramVar(TarBK); + if (TarBVar != nullptr) { + for (auto TB : AllVars) { + if (*(BI->getProgramVar(TB)->getScope()) == + *(TarBVar->getScope())) { + SameScopeVars.insert(TB); + } + } + // There is only one same scope variable. + // Consider only that. + if (SameScopeVars.size() == 1) { + AllVars.clear(); + AllVars.insert(*SameScopeVars.begin()); + return; + } + } // We want to merge all bounds vars. We give preference to // non-constants if there are multiple non-constant variables, // we give up. @@ -210,6 +229,9 @@ AvarBoundsInference::convergeInferredBounds() { } else if (BTypeMap.find(ABounds::ByteBoundKind) != BTypeMap.end() && !BTypeMap[ABounds::ByteBoundKind].empty()) { AB = new ByteBound(*BTypeMap[ABounds::ByteBoundKind].begin()); + } else if (BTypeMap.find(ABounds::CountPlusOneBoundKind) != BTypeMap.end() && + !BTypeMap[ABounds::CountPlusOneBoundKind].empty()) { + AB = new CountPlusOneBound(*BTypeMap[ABounds::CountPlusOneBoundKind].begin()); } // If we found any bounds? @@ -486,36 +508,7 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, AVarGraph &BKGraph, bool From if (BI->InvalidBounds.find(K) == BI->InvalidBounds.end()) { // Infer from potential bounds? if (FromPB) { - auto &PotBDs = BI->PotentialCntBounds; - if (PotBDs.find(K) != PotBDs.end()) { - ProgramVar *Kvar = BI->getProgramVar(K); - std::set PotentialB; - PotentialB.clear(); - for (auto TK : PotBDs[K]) - getReachableBoundKeys(Kvar->getScope(), TK, PotentialB, BKGraph, true); - - if (!PotentialB.empty()) { - bool Handled = false; - // Potential bounds are always count bounds. - // We use potential bounds - ABounds::BoundsKind PotKind = ABounds::CountBoundKind; - if (CurrIterInferBounds.find(K) != CurrIterInferBounds.end()) { - auto &BM = CurrIterInferBounds[K]; - // If we have any inferred bounds for K then ignore potential - // bounds. - for (auto &PosB : BM) { - if (!PosB.second.empty()) { - Handled = true; - break; - } - } - } - if (!Handled) { - CurrIterInferBounds[K][PotKind] = PotentialB; - IsChanged = true; - } - } - } + IsChanged = inferFromPotentialBounds(K, BKGraph); } else { // Infer from the flow-graph. std::set TmpBkeys; @@ -527,6 +520,86 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, AVarGraph &BKGraph, bool From return IsChanged; } +bool AvarBoundsInference::inferFromPotentialBounds(BoundsKey BK, + AVarGraph &BKGraph) { + bool IsChanged = false; + bool Handled = false; + if (CurrIterInferBounds.find(BK) != CurrIterInferBounds.end()) { + auto &BM = CurrIterInferBounds[BK]; + // If we have any inferred bounds for K then ignore potential + // bounds. + for (auto &PosB : BM) { + if (!PosB.second.empty()) { + Handled = true; + break; + } + } + } + + if (!Handled) { + auto &PotBDs = BI->PotBoundsInfo; + // Here, the logic is: + // We first try potential bounds and if there are no potential bounds? + // then, we check if there are count(i+1) bounds. + ProgramVar *Kvar = BI->getProgramVar(BK); + // These are potential count bounds. + ABounds::BoundsKind PotKind = ABounds::CountBoundKind; + std::set PotentialB; + if (PotBDs.hasPotentialCountBounds(BK)) { + for (auto TK : PotBDs.getPotentialBounds(BK)) + getReachableBoundKeys(Kvar->getScope(), TK, PotentialB, BKGraph, true); + } + if (PotentialB.empty() && PotBDs.hasPotentialCountPOneBounds(BK)) { + // These are potential count (i + 1) bounds. + PotKind = ABounds::CountPlusOneBoundKind; + for (auto TK : PotBDs.getPotentialBoundsPOne(BK)) + getReachableBoundKeys(Kvar->getScope(), TK, PotentialB, BKGraph, true); + } + if (!PotentialB.empty()) { + CurrIterInferBounds[BK][PotKind] = PotentialB; + IsChanged = true; + } + } + return IsChanged; +} + +bool PotentialBoundsInfo::hasPotentialCountBounds(BoundsKey PtrBK) { + return PotentialCntBounds.find(PtrBK) != PotentialCntBounds.end(); +} + +std::set &PotentialBoundsInfo::getPotentialBounds(BoundsKey PtrBK) { + assert(hasPotentialCountBounds(PtrBK) && "Has no potential bounds"); + return PotentialCntBounds[PtrBK]; +} + +void +PotentialBoundsInfo::addPotentialBounds(BoundsKey BK, + const std::set &PotK) { + if (!PotK.empty()) { + auto &TmpK = PotentialCntBounds[BK]; + TmpK.insert(PotK.begin(), PotK.end()); + } +} + +bool PotentialBoundsInfo::hasPotentialCountPOneBounds(BoundsKey PtrBK) { + return PotentialCntPOneBounds.find(PtrBK) != PotentialCntPOneBounds.end(); +} + +std::set & + PotentialBoundsInfo::getPotentialBoundsPOne(BoundsKey PtrBK) { + assert(hasPotentialCountPOneBounds(PtrBK) && + "Has no potential count+1 bounds"); + return PotentialCntPOneBounds[PtrBK]; +} +void +PotentialBoundsInfo::addPotentialBoundsPOne(BoundsKey BK, + const std::set &PotK) { + if (!PotK.empty()) { + auto &TmpK = PotentialCntPOneBounds[BK]; + TmpK.insert(PotK.begin(), PotK.end()); + } +} + bool AVarBoundsInfo::isValidBoundVariable(clang::Decl *D) { // All parameters, return, and field values are valid bound variables. if (D && (isa(D) || isa(D) || isa(D))) @@ -674,15 +747,18 @@ ABounds *AVarBoundsInfo::getBounds(BoundsKey L, BoundsPriority ReqP, return nullptr; } -bool AVarBoundsInfo::updatePotentialCountBounds(BoundsKey BK, - std::set &CntBK) { - bool RetVal = false; - if (!CntBK.empty()) { - auto &TmpK = PotentialCntBounds[BK]; - TmpK.insert(CntBK.begin(), CntBK.end()); - RetVal = true; - } - return RetVal; +bool +AVarBoundsInfo::updatePotentialCountBounds(BoundsKey BK, + const std::set &CntBK) { + PotBoundsInfo.addPotentialBounds(BK, CntBK); + return true; +} + +bool +AVarBoundsInfo::updatePotentialCountPOneBounds(BoundsKey BK, + const std::set &CntBK) { + PotBoundsInfo.addPotentialBoundsPOne(BK, CntBK); + return true; } void AVarBoundsInfo::insertVariable(clang::Decl *D) { @@ -1009,40 +1085,33 @@ void AVarBoundsInfo::insertProgramVar(BoundsKey NK, ProgramVar *PV) { bool AVarBoundsInfo::performWorkListInference(const std::set &ArrNeededBounds, AVarGraph &BKGraph, - AvarBoundsInference &BI) { + AvarBoundsInference &BI, + bool FromPB) { bool RetVal = false; std::set WorkList; std::set NextIterArrs; - std::vector FromBVals; - // We first infer with using only flow information - // i.e., without using any potential bounds. - FromBVals.push_back(false); - // Next, we try using potential bounds. - FromBVals.push_back(true); - for (auto FromPB : FromBVals) { - WorkList.clear(); - WorkList.insert(ArrNeededBounds.begin(), ArrNeededBounds.end()); - bool Changed = true; - while (Changed) { - Changed = false; - NextIterArrs.clear(); - // Are there any ARR atoms that need bounds? - while (!WorkList.empty()) { - BoundsKey CurrArrKey = *WorkList.begin(); - // Remove the bounds key from the worklist. - WorkList.erase(CurrArrKey); - // Can we find bounds for this Arr? - if (BI.inferBounds(CurrArrKey, BKGraph, FromPB)) { - RetVal = true; - Changed = true; - // Get all the successors of the ARR whose bounds we just found. - BKGraph.getSuccessors(CurrArrKey, NextIterArrs); - } - } - if (Changed) { - findIntersection(ArrNeededBounds, NextIterArrs, WorkList); + WorkList.clear(); + WorkList.insert(ArrNeededBounds.begin(), ArrNeededBounds.end()); + bool Changed = true; + while (Changed) { + Changed = false; + NextIterArrs.clear(); + // Are there any ARR atoms that need bounds? + while (!WorkList.empty()) { + BoundsKey CurrArrKey = *WorkList.begin(); + // Remove the bounds key from the worklist. + WorkList.erase(CurrArrKey); + // Can we find bounds for this Arr? + if (BI.inferBounds(CurrArrKey, BKGraph, FromPB)) { + RetVal = true; + Changed = true; + // Get all the successors of the ARR whose bounds we just found. + BKGraph.getSuccessors(CurrArrKey, NextIterArrs); } } + if (Changed) { + findIntersection(ArrNeededBounds, NextIterArrs, WorkList); + } } return RetVal; } @@ -1242,63 +1311,79 @@ bool AVarBoundsInfo::performFlowAnalysis(ProgramInfo *PI) { for (auto TBK : ArrPointerBoundsKey) removeBounds(TBK, FlowInferred); - std::set ArrNeededBounds, ArrNeededBoundsNew; + std::set ArrNeededBounds, ArrNeededBoundsNew, TmpArrNeededBounds; ArrNeededBounds.clear(); getBoundsNeededArrPointers(ArrPointers, ArrNeededBounds); - bool Changed = !ArrNeededBounds.empty(); + bool OuterChanged, InnerChanged; + std::vector FromBVals; + // We first infer with using only flow information + // i.e., without using any potential bounds. + FromBVals.push_back(false); + // Next, we try using potential bounds. + FromBVals.push_back(true); // Now compute the bounds information of all the ARR pointers that need it. // We iterate until there are no new array variables whose bounds are found. // The expectation is every iteration we will find bounds for at least one // array variable. - while (Changed) { - // Clear all inferred bounds. - ABI.clearInferredBounds(); - // Regular flow inference (with no edges between callers and callees). - performWorkListInference(ArrNeededBounds, this->ProgVarGraph, ABI); - - // Converge using local bounds (i.e., within each function). - // From all the sets of bounds computed for various array variables. - // Intersect them and find the common bound variable. - ABI.convergeInferredBounds(); - - ArrNeededBoundsNew.clear(); - getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); - // Now propagate the bounds information from context-sensitive keys - // to original keys (i.e., edges from callers to callees are present, - // but no local edges) - performWorkListInference(ArrNeededBoundsNew, this->CtxSensProgVarGraph, - ABI); - - ABI.convergeInferredBounds(); - // Now clear all inferred bounds so that context-sensitive nodes do not - // interfere with each other. - ABI.clearInferredBounds(); - ArrNeededBoundsNew.clear(); - // Get array variables that still need bounds. - getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); - - // Now propagate the bounds information from normal keys to - // context-sensitive keys. - performWorkListInference(ArrNeededBoundsNew, this->RevCtxSensProgVarGraph, - ABI); - - ABI.convergeInferredBounds(); - ArrNeededBoundsNew.clear(); - // Get array variables that still need bounds. - getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); - - // Did we find bounds for new array variables? - Changed = ArrNeededBounds != ArrNeededBoundsNew; - if (ArrNeededBounds.size() == ArrNeededBoundsNew.size()) { - assert(!Changed && "New arrays needed bounds after inference"); + TmpArrNeededBounds = ArrNeededBounds; + OuterChanged = !ArrNeededBounds.empty(); + while (OuterChanged) { + TmpArrNeededBounds = ArrNeededBounds; + for (auto FromPB : FromBVals) { + InnerChanged = !ArrNeededBounds.empty(); + while (InnerChanged) { + // Clear all inferred bounds. + ABI.clearInferredBounds(); + // Regular flow inference (with no edges between callers and callees). + performWorkListInference(ArrNeededBounds, this->ProgVarGraph, ABI, + FromPB); + + // Converge using local bounds (i.e., within each function). + // From all the sets of bounds computed for various array variables. + // Intersect them and find the common bound variable. + ABI.convergeInferredBounds(); + + ArrNeededBoundsNew.clear(); + getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); + // Now propagate the bounds information from context-sensitive keys + // to original keys (i.e., edges from callers to callees are present, + // but no local edges) + performWorkListInference(ArrNeededBoundsNew, this->CtxSensProgVarGraph, + ABI, FromPB); + + ABI.convergeInferredBounds(); + // Now clear all inferred bounds so that context-sensitive nodes do not + // interfere with each other. + ABI.clearInferredBounds(); + ArrNeededBoundsNew.clear(); + // Get array variables that still need bounds. + getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); + + // Now propagate the bounds information from normal keys to + // context-sensitive keys. + performWorkListInference(ArrNeededBoundsNew, + this->RevCtxSensProgVarGraph, ABI, FromPB); + + ABI.convergeInferredBounds(); + ArrNeededBoundsNew.clear(); + // Get array variables that still need bounds. + getBoundsNeededArrPointers(ArrPointers, ArrNeededBoundsNew); + + // Did we find bounds for new array variables? + InnerChanged = (ArrNeededBounds != ArrNeededBoundsNew); + if (ArrNeededBounds.size() == ArrNeededBoundsNew.size()) { + assert(!InnerChanged && "New arrays needed bounds after inference"); + } + assert(ArrNeededBoundsNew.size() <= ArrNeededBounds.size() && + "We should always have less number of arrays whose bounds needs " + "to be inferred after each round."); + ArrNeededBounds = ArrNeededBoundsNew; + } } - assert(ArrNeededBoundsNew.size() <= ArrNeededBounds.size() && - "We should always have less number of arrays whose bounds needs " - "to be inferred after each round."); - ArrNeededBounds = ArrNeededBoundsNew; + OuterChanged = (TmpArrNeededBounds != ArrNeededBounds); } PStats.endArrayBoundsInferenceTime(); diff --git a/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp b/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp index b1f986c3d35a..a7292292c731 100644 --- a/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp +++ b/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp @@ -886,6 +886,8 @@ void LengthVarInference::VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { CV.TraverseStmt(CDGNode->getTerminatorStmt()); } ABI.updatePotentialCountBounds(BasePtr, PossibleLens); + } else { + ABI.updatePotentialCountPOneBounds(BasePtr, {IdxKey}); } } } diff --git a/clang/test/3C/allarrays.c b/clang/test/3C/allarrays.c index 91e1ceea5bc3..7fb30c21d00f 100644 --- a/clang/test/3C/allarrays.c +++ b/clang/test/3C/allarrays.c @@ -8,7 +8,7 @@ void bar(void) { int *p = 0; //CHECK: _Array_ptr p = 0; int *q = foo(p); - //CHECK: _Array_ptr q = foo(p); + //CHECK: _Array_ptr q : count(1 + 1) = foo(p); q[1] = 0; } int *foo(int *r); diff --git a/clang/test/3C/arrboundsheuristics.c b/clang/test/3C/arrboundsheuristics.c index 67ad63b2e7c8..cc4fb7bc009c 100644 --- a/clang/test/3C/arrboundsheuristics.c +++ b/clang/test/3C/arrboundsheuristics.c @@ -15,7 +15,7 @@ int lenplusone; //CHECK_NOALL: int *glob; void foo(int *p, int idx) { p[idx] = 0; } -//CHECK_ALL: void foo(_Array_ptr p, int idx) { p[idx] = 0; } +//CHECK_ALL: void foo(_Array_ptr p : count(idx + 1), int idx) { p[idx] = 0; } //CHECK_NOALL: void foo(int *p : itype(_Ptr), int idx) { p[idx] = 0; } void bar(int *p, int flag) { diff --git a/clang/test/3C/arrctxsenbounds.c b/clang/test/3C/arrctxsenbounds.c index d0c2037d9df0..6332cd00f1a3 100644 --- a/clang/test/3C/arrctxsenbounds.c +++ b/clang/test/3C/arrctxsenbounds.c @@ -13,7 +13,7 @@ struct foo { unsigned fail_y_len; }; //CHECK: _Array_ptr x : count(olol); -//CHECK: _Array_ptr y; +//CHECK: _Array_ptr y : count(0 + 1); void ctx_(struct foo *f, struct foo *f2) { f2->y = f->x; diff --git a/clang/test/3C/lowerbound.c b/clang/test/3C/lowerbound.c index ce616a1138c3..e7de9af19b26 100644 --- a/clang/test/3C/lowerbound.c +++ b/clang/test/3C/lowerbound.c @@ -13,5 +13,5 @@ void bar() { y = foo(z); y[2] = 1; } -//CHECK: _Array_ptr y = 0; +//CHECK: _Array_ptr y : count(2 + 1) = 0; //CHECK-NEXT: _Array_ptr z = 0; diff --git a/clang/test/3C/malloc_array.c b/clang/test/3C/malloc_array.c index 288be66084f6..7dc493c7d20e 100644 --- a/clang/test/3C/malloc_array.c +++ b/clang/test/3C/malloc_array.c @@ -9,7 +9,7 @@ int *foo(int *x) { //CHECK_NOALL: int *foo(int *x : itype(_Ptr)) : itype(_Ptr) { - //CHECK_ALL: _Array_ptr foo(_Array_ptr x) _Checked { + //CHECK_ALL: _Array_ptr foo(_Array_ptr x : count(2 + 1)) : count(2 + 1) _Checked { x[2] = 1; return x; } @@ -20,7 +20,7 @@ void bar(void) { //CHECK: y = (int *)5; int *z = foo(y); //CHECK_NOALL: _Ptr z = foo(y); - //CHECK_ALL: _Ptr z = foo(_Assume_bounds_cast<_Array_ptr>(y, byte_count(0))); + //CHECK_ALL: _Ptr z = foo(_Assume_bounds_cast<_Array_ptr>(y, count(2 + 1))); } void force(int *x) {} diff --git a/clang/test/3C/multidef1a.c b/clang/test/3C/multidef1a.c index 75a8149e9e73..4851871e2550 100644 --- a/clang/test/3C/multidef1a.c +++ b/clang/test/3C/multidef1a.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) { } int foo(int argc, char **argv) { -//CHECK_ALL: int foo(int argc, _Array_ptr<_Nt_array_ptr> argv) _Checked { +//CHECK_ALL: int foo(int argc, _Array_ptr<_Nt_array_ptr> argv : count(0 + 1)) _Checked { //CHECK_NOALL: int foo(int argc, char **argv : itype(_Ptr<_Ptr>)) { char p = argv[0][0]; return 0; diff --git a/clang/test/3C/multidef1b.c b/clang/test/3C/multidef1b.c index 0e5890f9b0d1..19b8e738220e 100644 --- a/clang/test/3C/multidef1b.c +++ b/clang/test/3C/multidef1b.c @@ -19,7 +19,7 @@ int main(int argc, char **argv) { int foo(int argc, char **argv) { //CHECK_NOALL: int foo(int argc, char **argv : itype(_Ptr<_Ptr>)) { -//CHECK_ALL: int foo(int argc, _Array_ptr<_Nt_array_ptr> argv) _Checked { +//CHECK_ALL: int foo(int argc, _Array_ptr<_Nt_array_ptr> argv : count(0 + 1)) _Checked { if (argc > 1) { int x = strlen(argv[1]); return x; diff --git a/clang/test/3C/placements.c b/clang/test/3C/placements.c index 9aca5c883490..b9bc7388850b 100644 --- a/clang/test/3C/placements.c +++ b/clang/test/3C/placements.c @@ -11,11 +11,11 @@ // expected-no-diagnostics void what(const char *s, int q); //CHECK_NOALL: void what(const char *s : itype(_Ptr), int q); -//CHECK_ALL: void what(_Array_ptr s : count(q), int q); +//CHECK_ALL: void what(_Array_ptr s : count(5 + 1), int q); void what(const char *s, int q) { char v = s[5]; } //CHECK_NOALL: void what(const char *s : itype(_Ptr), int q) { char v = s[5]; } -//CHECK_ALL: void what(_Array_ptr s : count(q), int q) _Checked { char v = s[5]; } +//CHECK_ALL: void what(_Array_ptr s : count(5 + 1), int q) _Checked { char v = s[5]; } void foo(_Ptr a) { *a = 0; } //CHECK: void foo(_Ptr a) _Checked { *a = 0; } diff --git a/clang/test/3C/realloc.c b/clang/test/3C/realloc.c index e5f93bab438b..dd619a33df89 100644 --- a/clang/test/3C/realloc.c +++ b/clang/test/3C/realloc.c @@ -15,6 +15,6 @@ void foo(int *w) { y[1] = 3; int *z = realloc(y, 5 * sizeof(int)); //CHECK_NOALL: int *z = realloc(y, 5 * sizeof(int)); - //CHECK_ALL: _Array_ptr z = realloc(y, 5 * sizeof(int)); + //CHECK_ALL: _Array_ptr z : count(3 + 1) = realloc(y, 5 * sizeof(int)); z[3] = 2; } diff --git a/clang/test/3C/realloc_complex.c b/clang/test/3C/realloc_complex.c index 1a38097c0af1..45cebe7aaabd 100644 --- a/clang/test/3C/realloc_complex.c +++ b/clang/test/3C/realloc_complex.c @@ -42,10 +42,10 @@ void foo(int *count) { y[1] = 3; int *z = realloc(y, 5 * sizeof(int)); //CHECK_NOALL: int *z = realloc(y, 5 * sizeof(int)); - //CHECK_ALL: _Array_ptr z = realloc(y, 5 * sizeof(int)); + //CHECK_ALL: _Array_ptr z : count(3 + 1) = realloc(y, 5 * sizeof(int)); int *m = realloc(w, 2 * sizeof(int)); //CHECK_NOALL: int *m = realloc(w, 2 * sizeof(int)); - //CHECK_ALL: _Array_ptr m = realloc(w, 2 * sizeof(int)); + //CHECK_ALL: _Array_ptr m : count(1 + 1) = realloc(w, 2 * sizeof(int)); m[1] = 5; z[3] = 2; } diff --git a/clang/test/3C/refarrsubscript.c b/clang/test/3C/refarrsubscript.c index 5db9dfee6d95..607526e5725b 100644 --- a/clang/test/3C/refarrsubscript.c +++ b/clang/test/3C/refarrsubscript.c @@ -7,19 +7,19 @@ int **func(int **p, int *x) { //CHECK_NOALL: int **func(int **p : itype(_Ptr<_Ptr>), _Ptr x) : itype(_Ptr) { - //CHECK_ALL: _Array_ptr<_Ptr> func(_Array_ptr<_Ptr> p, _Ptr x) _Checked { + //CHECK_ALL: _Array_ptr<_Ptr> func(_Array_ptr<_Ptr> p : count(1 + 1), _Ptr x) : count(1 + 1) _Checked { return &(p[1]); } struct foo { int **b; //CHECK_NOALL: int **b; - //CHECK_ALL: _Array_ptr<_Ptr> b; + //CHECK_ALL: _Array_ptr<_Ptr> b : count(1 + 1); int n; }; int **bar(struct foo *p) { //CHECK_NOALL: int **bar(_Ptr p) : itype(_Ptr) { - //CHECK_ALL: _Array_ptr<_Ptr> bar(_Ptr p) _Checked { + //CHECK_ALL: _Array_ptr<_Ptr> bar(_Ptr p) : count(1 + 1) _Checked { int *n = &p->n; //CHECK: _Ptr n = &p->n; return &(p->b[1]); diff --git a/clang/test/3C/resolve_itypes.c b/clang/test/3C/resolve_itypes.c index ce6ebe83ce1c..d83c1950b7bb 100644 --- a/clang/test/3C/resolve_itypes.c +++ b/clang/test/3C/resolve_itypes.c @@ -7,7 +7,7 @@ void foo(int *a : itype(_Ptr)) { //CHECK_NOALL: void foo(int *a : itype(_Ptr)) { -//CHECK_ALL: void foo(int *a : itype(_Array_ptr)) { +//CHECK_ALL: void foo(int *a : itype(_Array_ptr) count(0 + 1)) { a = (int*) 1; (void) a[0]; } diff --git a/clang/test/3C/simple_locals.c b/clang/test/3C/simple_locals.c index 02e12f9a4596..f879df874fae 100644 --- a/clang/test/3C/simple_locals.c +++ b/clang/test/3C/simple_locals.c @@ -117,11 +117,11 @@ int baz(int *a, int b, int c) { //CHECK-NEXT: return tmp; int arrcheck(int *a, int b) { return a[b]; } -//CHECK_ALL: int arrcheck(_Array_ptr a : count(b), int b) _Checked { return a[b]; } +//CHECK_ALL: int arrcheck(_Array_ptr a : count(b + 1), int b) _Checked { return a[b]; } //CHECK_NOALL: int arrcheck(int *a : itype(_Ptr), int b) { return a[b]; } int badcall(int *a, int b) { return arrcheck(a, b); } -//CHECK_ALL: int badcall(_Array_ptr a : count(b), int b) _Checked { return arrcheck(a, b); } +//CHECK_ALL: int badcall(_Array_ptr a : count(b + 1), int b) _Checked { return arrcheck(a, b); } //CHECK_NOALL: int badcall(_Ptr a, int b) _Checked { return arrcheck(a, b); } void pullit(char *base, char *out, int *index) { diff --git a/clang/test/3C/untypedprototypes.c b/clang/test/3C/untypedprototypes.c index 543dd2ec4caa..954f8b1c3058 100644 --- a/clang/test/3C/untypedprototypes.c +++ b/clang/test/3C/untypedprototypes.c @@ -3,17 +3,17 @@ // RUN: 3c -base-dir=%S -alltypes %s -- | %clang -c -f3c-tool -fcheckedc-extension -x c -o %t.unused - int *foo(); -//CHECK: _Array_ptr foo(_Array_ptr q); +//CHECK: _Array_ptr foo(_Array_ptr q) : count(10 + 1); void bar(void) { int *x = 0; //CHECK: _Array_ptr x = 0; int *y = foo(x); - //CHECK: _Array_ptr y = foo(x); + //CHECK: _Array_ptr y : count(10 + 1) = foo(x); y[10] = 1; } int *foo(int *q) { - //CHECK: _Array_ptr foo(_Array_ptr q) { + //CHECK: _Array_ptr foo(_Array_ptr q) : count(10 + 1) { return q; } From a83c986d36ec94c2962cc6cd0d5ca2c14252dd27 Mon Sep 17 00:00:00 2001 From: Aravind Machiry Date: Mon, 14 Jun 2021 00:29:00 -0400 Subject: [PATCH 2/3] Fixing Review comments --- clang/include/clang/3C/AVarBoundsInfo.h | 4 ++-- clang/lib/3C/ABounds.cpp | 23 ++++++++--------------- clang/lib/3C/AVarBoundsInfo.cpp | 6 ++---- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/3C/AVarBoundsInfo.h b/clang/include/clang/3C/AVarBoundsInfo.h index 95550221856c..2f857bcaf832 100644 --- a/clang/include/clang/3C/AVarBoundsInfo.h +++ b/clang/include/clang/3C/AVarBoundsInfo.h @@ -198,9 +198,9 @@ class AVarBoundsInfo { bool replaceBounds(BoundsKey L, BoundsPriority P, ABounds *B); ABounds *getBounds(BoundsKey L, BoundsPriority ReqP = Invalid, BoundsPriority *RetP = nullptr); - bool updatePotentialCountBounds(BoundsKey BK, + void updatePotentialCountBounds(BoundsKey BK, const std::set &CntBK); - bool updatePotentialCountPOneBounds(BoundsKey BK, + void updatePotentialCountPOneBounds(BoundsKey BK, const std::set &CntBK); // Try and get BoundsKey, into R, for the given declaration. If the diff --git a/clang/lib/3C/ABounds.cpp b/clang/lib/3C/ABounds.cpp index 0e2f06c3988f..43438eaab3dd 100644 --- a/clang/lib/3C/ABounds.cpp +++ b/clang/lib/3C/ABounds.cpp @@ -97,11 +97,10 @@ std::string CountPlusOneBound::mkString(AVarBoundsInfo *ABI, clang::Decl *D) { std::string CVar = ABounds::getBoundsKeyStr(CountVar, ABI, D); return "count(" + CVar + " + 1)"; } + bool CountPlusOneBound::areSame(ABounds *O, AVarBoundsInfo *ABI) { - if (O != nullptr) { - if (CountPlusOneBound *OT = dyn_cast(O)) - return ABI->areSameProgramVar(this->CountVar, OT->CountVar); - } + if (CountPlusOneBound *OT = dyn_cast_or_null(O)) + return ABI->areSameProgramVar(this->CountVar, OT->CountVar); return false; } @@ -110,11 +109,8 @@ std::string ByteBound::mkString(AVarBoundsInfo *ABI, clang::Decl *D) { } bool ByteBound::areSame(ABounds *O, AVarBoundsInfo *ABI) { - if (O != nullptr) { - if (ByteBound *BB = dyn_cast(O)) { - return ABI->areSameProgramVar(this->ByteVar, BB->ByteVar); - } - } + if (ByteBound *BB = dyn_cast_or_null(O)) + return ABI->areSameProgramVar(this->ByteVar, BB->ByteVar); return false; } @@ -130,11 +126,8 @@ std::string RangeBound::mkString(AVarBoundsInfo *ABI, clang::Decl *D) { } bool RangeBound::areSame(ABounds *O, AVarBoundsInfo *ABI) { - if (O != nullptr) { - if (RangeBound *RB = dyn_cast(O)) { - return ABI->areSameProgramVar(this->LB, RB->LB) && - ABI->areSameProgramVar(this->UB, RB->UB); - } - } + if (RangeBound *RB = dyn_cast_or_null(O)) + return ABI->areSameProgramVar(this->LB, RB->LB) && + ABI->areSameProgramVar(this->UB, RB->UB); return false; } diff --git a/clang/lib/3C/AVarBoundsInfo.cpp b/clang/lib/3C/AVarBoundsInfo.cpp index d2a63726dd76..8e451f3931f7 100644 --- a/clang/lib/3C/AVarBoundsInfo.cpp +++ b/clang/lib/3C/AVarBoundsInfo.cpp @@ -747,18 +747,16 @@ ABounds *AVarBoundsInfo::getBounds(BoundsKey L, BoundsPriority ReqP, return nullptr; } -bool +void AVarBoundsInfo::updatePotentialCountBounds(BoundsKey BK, const std::set &CntBK) { PotBoundsInfo.addPotentialBounds(BK, CntBK); - return true; } -bool +void AVarBoundsInfo::updatePotentialCountPOneBounds(BoundsKey BK, const std::set &CntBK) { PotBoundsInfo.addPotentialBoundsPOne(BK, CntBK); - return true; } void AVarBoundsInfo::insertVariable(clang::Decl *D) { From 431ba7c26a40981816a1eba54c3f7624b6d7b817 Mon Sep 17 00:00:00 2001 From: Aravind Machiry Date: Mon, 14 Jun 2021 23:18:38 -0400 Subject: [PATCH 3/3] Fixing issue where the declaration has only types --- clang/lib/3C/ABounds.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/3C/ABounds.cpp b/clang/lib/3C/ABounds.cpp index 43438eaab3dd..507b0c8740f0 100644 --- a/clang/lib/3C/ABounds.cpp +++ b/clang/lib/3C/ABounds.cpp @@ -72,6 +72,10 @@ std::string ABounds::getBoundsKeyStr(BoundsKey BK, if (FD->getNumParams() > PIdx) { auto *NewPVD = FD->getParamDecl(PIdx); BKStr = NewPVD->getNameAsString(); + // If the parameter in the new declaration does not have a name? + // then use the old name. + if (BKStr.empty()) + BKStr = PV->mkString(); } } return BKStr;