baloghadamsoftware created this revision. baloghadamsoftware added a reviewer: NoQ. baloghadamsoftware added a project: clang. Herald added subscribers: ASDenysPetrov, martong, steakhal, Charusso, gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun, whisperity. Herald added a reviewer: Szelethus. baloghadamsoftware added a comment.
Testing this patch on `test/Analysis/iterator-modeling.cpp` crashes with the following output: Handling operator++() Return Value: lazyCompoundVal{0x55655390c9d8,i1} Bingo! State->get<ObjectsUnderConstruction>(Key): &i1 Key.getItem().getKind(): 0 clang: /home/edmbalo/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp:472: static clang::ento::ProgramStateRef clang::ento::ExprEngine::addObjectUnderConstruction(clang::ento::ProgramStateRef, const clang::ConstructionContextItem&, const clang::LocationContext*, clang::ento::SVal): Assertion `!State->get<ObjectsUnderConstruction>(Key) || Key.getItem().getKind() == ConstructionContextItem::TemporaryDestructorKind' failed. ... What could be the problem here? Since accessing the region of LazyCompoundVals is an undocumented and unreliable feature, try to find the region of the return value directly, skipping both the LazyCompoundVal and its later materialization. This patch is work in progress. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77229 Files: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp clang/lib/StaticAnalyzer/Core/CallEvent.cpp clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -464,9 +464,12 @@ ConstructedObjectKey Key(Item, LC->getStackFrame()); // FIXME: Currently the state might already contain the marker due to // incorrect handling of temporaries bound to default parameters. + if (State->get<ObjectsUnderConstruction>(Key)) + llvm::errs()<<"State->get<ObjectsUnderConstruction>(Key): "<<*State->get<ObjectsUnderConstruction>(Key)<<"\n"; + llvm::errs()<<"Key.getItem().getKind(): "<<Key.getItem().getKind()<<"\n"; assert(!State->get<ObjectsUnderConstruction>(Key) || Key.getItem().getKind() == - ConstructionContextItem::TemporaryDestructorKind); + ConstructionContextItem::TemporaryDestructorKind); return State->set<ObjectsUnderConstruction>(Key, V); } Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -257,6 +257,24 @@ return VR; } +const ConstructionContext +*CallEvent::getConstructionContext(unsigned BlockCount) const { + const StackFrameContext *StackFrame = getCalleeStackFrame(BlockCount); + if (!StackFrame) + return nullptr; + + const CFGBlock *Block = StackFrame->getCallSiteBlock(); + if (!Block) + return nullptr; + + const auto RecCall = + (*Block)[StackFrame->getIndex()].getAs<CFGCXXRecordTypedCall>(); + if (!RecCall) + return nullptr; + + return RecCall->getConstructionContext(); +} + /// Returns true if a type is a pointer-to-const or reference-to-const /// with no further indirection. static bool isPointerToConst(QualType Ty) { Index: clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -301,61 +301,74 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, const CallEvent &Call, OverloadedOperatorKind Op) const { - if (isSimpleComparisonOperator(Op)) { - const auto *OrigExpr = Call.getOriginExpr(); - if (!OrigExpr) - return; + const auto *OrigExpr = Call.getOriginExpr(); + if (!OrigExpr) + return; - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - handleComparison(C, OrigExpr, Call.getReturnValue(), - InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); - return; - } + if (isSimpleComparisonOperator(Op)) { + const auto *OrigExpr = Call.getOriginExpr(); + if (!OrigExpr) + return; - handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), - Call.getArgSVal(1), Op); + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + handleComparison(C, OrigExpr, Call.getReturnValue(), + InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); return; - } else if (isRandomIncrOrDecrOperator(Op)) { - const auto *OrigExpr = Call.getOriginExpr(); - if (!OrigExpr) - return; + } - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - if (Call.getNumArgs() >= 1 && - Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), - InstCall->getCXXThisVal(), Call.getArgSVal(0)); - return; - } - } else { - if (Call.getNumArgs() >= 2 && - Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), - Call.getArgSVal(0), Call.getArgSVal(1)); - return; - } + handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), + Call.getArgSVal(1), Op); + return; + } else if (isRandomIncrOrDecrOperator(Op)) { + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + if (Call.getNumArgs() >= 1 && + Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), + InstCall->getCXXThisVal(), Call.getArgSVal(0)); + return; } - } else if (isIncrementOperator(Op)) { - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), - Call.getNumArgs()); + } else { + if (Call.getNumArgs() >= 2 && + Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), + Call.getArgSVal(0), Call.getArgSVal(1)); return; } - - handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0), + } + } else if (isIncrementOperator(Op)) { + llvm::errs()<<"Handling operator++()\n"; + llvm::errs()<<" Return Value: "<<Call.getReturnValue()<<"\n"; + if (const auto *CC = Call.getConstructionContext(C.blockCount())) { + llvm::errs()<<" Bingo!\n"; + auto &Engine = C.getExprEngine(); + ExprEngine::EvalCallOptions CallOpts; + ProgramStateRef State; + SVal RetVal; + std::tie(State, RetVal) = + Engine.handleConstructionContext(OrigExpr, C.getState(), + C.getLocationContext(), CC, CallOpts); + llvm::errs()<<" Return Value 2: "<<RetVal<<"\n"; + } + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getNumArgs()); return; - } else if (isDecrementOperator(Op)) { - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), - Call.getNumArgs()); - return; - } + } - handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0), - Call.getNumArgs()); + handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0), + Call.getNumArgs()); + return; + } else if (isDecrementOperator(Op)) { + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), + Call.getNumArgs()); return; } + + handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0), + Call.getNumArgs()); + return; + } } void Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -686,6 +686,16 @@ const CallEvent &Call, const EvalCallOptions &CallOpts = {}); + /// Update the program state with all the path-sensitive information + /// that's necessary to perform construction of an object with a given + /// syntactic construction context. If the construction context is unavailable + /// or unusable for any reason, a dummy temporary region is returned, and the + /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts. + /// Returns the updated program state and the new object's this-region. + std::pair<ProgramStateRef, SVal> handleConstructionContext( + const Expr *E, ProgramStateRef State, const LocationContext *LCtx, + const ConstructionContext *CC, EvalCallOptions &CallOpts); + private: ProgramStateRef finishArgumentConstruction(ProgramStateRef State, const CallEvent &Call); @@ -804,16 +814,6 @@ /// constructing into an existing region. const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); - /// Update the program state with all the path-sensitive information - /// that's necessary to perform construction of an object with a given - /// syntactic construction context. If the construction context is unavailable - /// or unusable for any reason, a dummy temporary region is returned, and the - /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts. - /// Returns the updated program state and the new object's this-region. - std::pair<ProgramStateRef, SVal> handleConstructionContext( - const Expr *E, ProgramStateRef State, const LocationContext *LCtx, - const ConstructionContext *CC, EvalCallOptions &CallOpts); - /// Common code that handles either a CXXConstructExpr or a /// CXXInheritedCtorInitExpr. void handleConstructor(const Expr *E, ExplodedNode *Pred, Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -52,6 +52,10 @@ "We should not call the checkers on an empty state."); } + ExprEngine &getExprEngine() { + return Eng; + } + AnalysisManager &getAnalysisManager() { return Eng.getAnalysisManager(); } Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -431,6 +431,10 @@ return CallArgumentIndex; } + /// If the call returns a C++ record type then the call has a construction + /// context from where the region of its return value can be retrieved. + const ConstructionContext *getConstructionContext(unsigned BlockCount) const; + // Iterator access to formal parameters and their types. private: struct GetTypeFn {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits