diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -139,7 +139,7 @@ if (RD->getDeclName().isIdentifier()) { StringRef Name = RD->getName(); - return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr"; + return llvm::is_contained(STD_PTR_NAMES, Name); } return false; } @@ -275,6 +275,29 @@ smartptr::isStdSmartPtr(Call.getArgExpr(1)); } +ProgramStateRef +invalidateInnerPointer(const MemRegion *ThisRegion, ProgramStateRef State, + const CallEvent &Call, CheckerContext &C) { + const auto *InnerPtrVal = State->get(ThisRegion); + if (InnerPtrVal) { + State = State->invalidateRegions(*InnerPtrVal, nullptr, C.blockCount(), + C.getLocationContext(), true); + + const QualType &Type = getInnerPointerType(Call, C); + const auto *RD = Type->getAsCXXRecordDecl(); + if (!RD) + return State; + const auto *DD = RD->getDestructor(); + + const auto InnerDestrCall = + C.getStateManager().getCallEventManager().getCXXDestructorCall( + DD, nullptr, InnerPtrVal->getAsRegion(), RD->bases().empty(), State, + C.getLocationContext()); + InnerDestrCall->invalidateRegions(C.blockCount(), State); + } + return State; +} + bool SmartPtrModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { @@ -372,6 +395,21 @@ } } + if (const auto *DC = dyn_cast(&Call)) { + const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) + return false; + State = State->remove(ThisRegion); + State = invalidateInnerPointer(ThisRegion, State, Call, C); + // This tag is required to prevent later crashes due to the non-addition + // of new States. Having a tag ensures that the call to addTransition + // actually adds a new state. + static SimpleProgramPointTag SPPT("SmartPtrModeling", + "on destructor modeling"); + C.addTransition(State, &SPPT); + return true; + } + if (!ModelSmartPtrDereference) return false; @@ -402,10 +440,14 @@ })); } else { const auto *TrackingExpr = Call.getArgExpr(0); - assert(TrackingExpr->getType()->isPointerType() && - "Adding a non pointer value to TrackedRegionMap"); + if (!TrackingExpr->getType()->isPointerType()) + return false; auto ArgVal = Call.getArgSVal(0); State = State->set(ThisRegion, ArgVal); + // Escape the pointer passed here + State = C.getStateManager().getOwningEngine().processPointerEscapedOnBind( + State, {std::make_pair(CC->getCXXThisVal(), ArgVal)}, + C.getLocationContext(), PSK_DirectEscapeOnCall, &Call); C.addTransition(State, C.getNoteTag([ThisRegion, TrackingExpr, ArgVal](PathSensitiveBugReport &BR, @@ -561,10 +603,8 @@ Out << Sep << "Smart ptr regions :" << NL; for (auto I : RS) { I.first->dumpToStream(Out); - if (smartptr::isNullSmartPtr(State, I.first)) - Out << ": Null"; - else - Out << ": Non Null"; + Out << ": "; + I.second.dumpToStream(Out); Out << NL; } } @@ -609,7 +649,13 @@ assert(Call.getArgExpr(0)->getType()->isPointerType() && "Adding a non pointer value to TrackedRegionMap"); - State = State->set(ThisRegion, Call.getArgSVal(0)); + State = invalidateInnerPointer(ThisRegion, State, Call, C); + const auto ArgVal = Call.getArgSVal(0); + State = State->set(ThisRegion, ArgVal); + // Escape the pointer passed here + State = C.getStateManager().getOwningEngine().processPointerEscapedOnBind( + State, {std::make_pair(IC->getCXXThisVal(), ArgVal)}, + C.getLocationContext(), PSK_DirectEscapeOnCall, &Call); const auto *TrackingExpr = Call.getArgExpr(0); C.addTransition( State, C.getNoteTag([ThisRegion, TrackingExpr](PathSensitiveBugReport &BR, diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -664,14 +664,11 @@ for (const auto &EvalCallChecker : EvalCallCheckers) { // TODO: Support the situation when the call doesn't correspond // to any Expr. - ProgramPoint L = ProgramPoint::getProgramPoint( - Call.getOriginExpr(), ProgramPoint::PostStmtKind, - Pred->getLocationContext(), EvalCallChecker.Checker); bool evaluated = false; { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. - CheckerContext C(B, Eng, Pred, L); + CheckerContext C(B, Eng, Pred, Call.getProgramPoint()); evaluated = EvalCallChecker(Call, C); } assert(!(evaluated && anyEvaluated) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -753,10 +753,13 @@ *Call, *this); ExplodedNodeSet DstInvalidated; - StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); - for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); - I != E; ++I) - defaultEvalCall(Bldr, *I, *Call, CallOpts); + // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); + // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = + // DstPreCall.end(); + // I != E; ++I) + // defaultEvalCall(Bldr, *I, *Call, CallOpts); + getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call, + *this, CallOpts); getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, *Call, *this);