ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State) { const Expr *E = Call.getOriginExpr(); if (!E) return State; // Some method families have known return values. if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { switch (Msg->getMethodFamily()) { default: break; case OMF_autorelease: case OMF_retain: case OMF_self: { // These methods return their receivers. return State->BindExpr(E, LCtx, Msg->getReceiverSVal()); } } } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){ return State->BindExpr(E, LCtx, C->getCXXThisVal()); } // Conjure a symbol if the return value is unknown. QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); unsigned Count = currBldrCtx->blockCount(); SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); }
void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call) { // Try to inline the call. ProgramStateRef state = 0; const Expr *E = Call.getOriginExpr(); if (E) { state = getInlineFailedState(Pred, E); if (state == 0 && inlineCall(Dst, Call, Pred)) return; } // If we can't inline it, handle the return value and invalidate the regions. StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); // Invalidate any regions touched by the call. unsigned Count = currentBuilderContext->getCurrentBlockCount(); if (state == 0) state = Pred->getState(); state = Call.invalidateRegions(Count, state); // Conjure a symbol value to use as the result. assert(Call.getOriginExpr() && "Must have an expression to bind the result"); QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); const LocationContext *LCtx = Pred->getLocationContext(); SVal RetVal = SVB.getConjuredSymbolVal(0, Call.getOriginExpr(), LCtx, ResultTy, Count); // And make the result node. state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal); Bldr.generateNode(Call.getOriginExpr(), Pred, state); }
void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call) { // 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. const Expr *E = Call.getOriginExpr(); ProgramStateRef state = getInlineFailedState(Pred, E); if (state == 0 && inlineCall(Dst, Call, Pred)) return; // If we can't inline it, handle the return value and invalidate the regions. NodeBuilder Bldr(Pred, Dst, *currentBuilderContext); // Invalidate any regions touched by the call. unsigned Count = currentBuilderContext->getCurrentBlockCount(); if (state == 0) state = Pred->getState(); state = Call.invalidateRegions(Count, state); // Conjure a symbol value to use as the result. if (E) { QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); const LocationContext *LCtx = Pred->getLocationContext(); SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count); state = state->BindExpr(E, LCtx, RetVal); } // And make the result node. Bldr.generateNode(Call.getProgramPoint(), state, Pred); }
ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State) { const Expr *E = Call.getOriginExpr(); if (!E) return State; // Some method families have known return values. if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { switch (Msg->getMethodFamily()) { default: break; case OMF_autorelease: case OMF_retain: case OMF_self: { // These methods return their receivers. return State->BindExpr(E, LCtx, Msg->getReceiverSVal()); } } } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){ SVal ThisV = C->getCXXThisVal(); // If the constructed object is a temporary prvalue, get its bindings. if (isTemporaryPRValue(cast<CXXConstructExpr>(E), ThisV)) ThisV = State->getSVal(ThisV.castAs<Loc>()); return State->BindExpr(E, LCtx, ThisV); } // Conjure a symbol if the return value is unknown. QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); unsigned Count = currBldrCtx->blockCount(); // See if we need to conjure a heap pointer instead of // a regular unknown pointer. bool IsHeapPointer = false; if (const auto *CNE = dyn_cast<CXXNewExpr>(E)) if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { // FIXME: Delegate this to evalCall in MallocChecker? IsHeapPointer = true; } SVal R = IsHeapPointer ? SVB.getConjuredHeapSymbolVal(E, LCtx, Count) : SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); }
void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const { const Expr *CallE = Call.getOriginExpr(); if (!CallE) return; unsigned Indentation = 0; for (const LocationContext *LC = C.getLocationContext()->getParent(); LC != nullptr; LC = LC->getParent()) ++Indentation; // It is mildly evil to print directly to llvm::outs() rather than emitting // warnings, but this ensures things do not get filtered out by the rest of // the static analyzer machinery. llvm::outs().indent(Indentation); if (Call.getResultType()->isVoidType()) llvm::outs() << "Returning void\n"; else llvm::outs() << "Returning " << C.getSVal(CallE) << "\n"; }
void IteratorChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Record new iterator positions and iterator position changes const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); if (!Func) return; if (Func->isOverloadedOperator()) { const auto Op = Func->getOverloadedOperator(); if (isSimpleComparisonOperator(Op)) { if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); } else { handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1), Op); } } } else { const auto *OrigExpr = Call.getOriginExpr(); if (!OrigExpr) return; if (!isIteratorType(Call.getResultType())) return; auto State = C.getState(); // Already bound to container? if (getIteratorPosition(State, Call.getReturnValue())) return; if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { if (isEndCall(Func)) { handleEnd(C, OrigExpr, Call.getReturnValue(), InstCall->getCXXThisVal()); return; } } // Copy-like and move constructors if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) { State = setIteratorPosition(State, Call.getReturnValue(), *Pos); if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) { State = removeIteratorPosition(State, Call.getArgSVal(0)); } C.addTransition(State); return; } } // Assumption: if return value is an iterator which is not yet bound to a // container, then look for the first iterator argument, and // bind the return value to the same container. This approach // works for STL algorithms. // FIXME: Add a more conservative mode for (unsigned i = 0; i < Call.getNumArgs(); ++i) { if (isIteratorType(Call.getArgExpr(i)->getType())) { if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) { assignToContainer(C, OrigExpr, Call.getReturnValue(), Pos->getContainer()); return; } } } } }