Region = makeZeroElementRegion(state, loc::MemRegionVal(Region), varType,
CallOpts.IsArrayCtorOrDtor).getAsRegion();
- VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false,
- Pred, Dst, CallOpts);
+ VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(),
+ /*IsBase=*/false, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
Base->isVirtual());
- VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(),
- CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst, {});
+ EvalCallOptions CallOpts;
+ VisitCXXDestructor(BaseTy, BaseVal.getAsRegion(), CurDtor->getBody(),
+ /*IsBase=*/true, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
const LocationContext *LCtx = Pred->getLocationContext();
const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
- Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
- LCtx->getStackFrame());
- SVal FieldVal =
- State->getLValue(Member, State->getSVal(ThisVal).castAs<Loc>());
+ Loc ThisStorageLoc =
+ getSValBuilder().getCXXThis(CurDtor, LCtx->getStackFrame());
+ Loc ThisLoc = State->getSVal(ThisStorageLoc).castAs<Loc>();
+ SVal FieldVal = State->getLValue(Member, ThisLoc);
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
FieldVal = makeZeroElementRegion(State, FieldVal, T,
CallOpts.IsArrayCtorOrDtor);
- VisitCXXDestructor(T, FieldVal.castAs<loc::MemRegionVal>().getRegion(),
- CurDtor->getBody(), /*IsBase=*/false, Pred, Dst, CallOpts);
+ VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(),
+ /*IsBase=*/false, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
EvalCallOptions CallOpts;
CallOpts.IsTemporaryCtorOrDtor = true;
if (!MR) {
- CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
-
// If we have no MR, we still need to unwrap the array to avoid destroying
// the whole array at once. Regardless, we'd eventually need to model array
// destructors properly, element-by-element.
bool IsBaseDtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst,
- const EvalCallOptions &CallOpts) {
+ EvalCallOptions &CallOpts) {
assert(S && "A destructor without a trigger!");
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
-
// FIXME: There should always be a Decl, otherwise the destructor call
// shouldn't have been added to the CFG in the first place.
if (!DtorDecl) {
return;
}
+ if (!Dest) {
+ // We're trying to destroy something that is not a region. This may happen
+ // for a variety of reasons (unknown target region, concrete integer instead
+ // of target region, etc.). The current code makes an attempt to recover.
+ // FIXME: We probably don't really need to recover when we're dealing
+ // with concrete integers specifically.
+ CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
+ if (const Expr *E = dyn_cast_or_null<Expr>(S)) {
+ Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getLocationContext());
+ } else {
+ static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateSink(Pred->getLocation().withTag(&T),
+ Pred->getState(), Pred);
+ return;
+ }
+ }
+
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
+ CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),