void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CXXConstructorCall &Call) { const CXXConstructExpr *CtorExpr = Call.getOriginExpr(); assert(CtorExpr->getConstructor()->isCopyOrMoveConstructor()); assert(CtorExpr->getConstructor()->isTrivial()); SVal ThisVal = Call.getCXXThisVal(); const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // Make sure the value being copied is not unknown. if (const Loc *L = dyn_cast<Loc>(&V)) V = Pred->getState()->getSVal(*L); evalBind(Dst, CtorExpr, Pred, ThisVal, V, true); PostStmt PS(CtorExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call) { ProgramStateRef State = 0; const Expr *E = Call.getOriginExpr(); // Try to inline the call. // The origin expression here is just used as a kind of checksum; // for CallEvents that do not have origin expressions, this should still be // safe. if (!isa<ObjCMethodCall>(Call)) { State = getInlineFailedState(Pred->getState(), E); if (State == 0 && inlineCall(Call, Pred)) { // If we inlined the call, the successor has been manually added onto // the work list and we should not consider it for subsequent call // handling steps. Bldr.takeNodes(Pred); return; } } // If we can't inline it, handle the return value and invalidate the regions. if (State == 0) State = Pred->getState(); // Invalidate any regions touched by the call. unsigned Count = currentBuilderContext->getCurrentBlockCount(); State = Call.invalidateRegions(Count, State); // Construct and bind the return value. State = bindReturnValue(Call, Pred->getLocationContext(), State); // And make the result node. Bldr.generateNode(Call.getProgramPoint(), State, Pred); }
// Conservatively evaluate call by invalidating regions and binding // a conjured return value. void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State) { State = Call.invalidateRegions(currBldrCtx->blockCount(), State); State = bindReturnValue(Call, Pred->getLocationContext(), State); // And make the result node. Bldr.generateNode(Call.getProgramPoint(), State, Pred); }
// FIXME: This is the sort of code that should eventually live in a Core // checker rather than as a special case in ExprEngine. void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call) { SVal ThisVal; bool AlwaysReturnsLValue; const CXXRecordDecl *ThisRD = nullptr; if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { assert(Ctor->getDecl()->isTrivial()); assert(Ctor->getDecl()->isCopyOrMoveConstructor()); ThisVal = Ctor->getCXXThisVal(); ThisRD = Ctor->getDecl()->getParent(); AlwaysReturnsLValue = false; } else { assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial()); assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() == OO_Equal); ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal(); ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent(); AlwaysReturnsLValue = true; } assert(ThisRD); if (ThisRD->isEmpty()) { // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal // and bind it and RegionStore would think that the actual value // in this region at this offset is unknown. return; } const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // If the value being copied is not unknown, load from its location to get // an aggregate rvalue. if (Optional<Loc> L = V.getAs<Loc>()) V = Pred->getState()->getSVal(*L); else assert(V.isUnknownOrUndef()); const Expr *CallExpr = Call.getOriginExpr(); evalBind(Dst, CallExpr, Pred, ThisVal, V, true); PostStmt PS(CallExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (AlwaysReturnsLValue) State = State->BindExpr(CallExpr, LCtx, ThisVal); else State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }
// FIXME: This is the sort of code that should eventually live in a Core // checker rather than as a special case in ExprEngine. void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call) { SVal ThisVal; bool AlwaysReturnsLValue; if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { assert(Ctor->getDecl()->isTrivial()); assert(Ctor->getDecl()->isCopyOrMoveConstructor()); ThisVal = Ctor->getCXXThisVal(); AlwaysReturnsLValue = false; } else { assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial()); assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() == OO_Equal); ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal(); AlwaysReturnsLValue = true; } const LocationContext *LCtx = Pred->getLocationContext(); ExplodedNodeSet Dst; Bldr.takeNodes(Pred); SVal V = Call.getArgSVal(0); // If the value being copied is not unknown, load from its location to get // an aggregate rvalue. if (Optional<Loc> L = V.getAs<Loc>()) V = Pred->getState()->getSVal(*L); else assert(V.isUnknown()); const Expr *CallExpr = Call.getOriginExpr(); evalBind(Dst, CallExpr, Pred, ThisVal, V, true); PostStmt PS(CallExpr, LCtx); for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (AlwaysReturnsLValue) State = State->BindExpr(CallExpr, LCtx, ThisVal); else State = bindReturnValue(Call, LCtx, State); Bldr.generateNode(PS, State, *I); } }