123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- //===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- C++ -*-===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines the C++ expression evaluation engine.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/StaticAnalyzer/Core/CheckerManager.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
- #include "clang/AST/DeclCXX.h"
- using namespace clang;
- using namespace ento;
- namespace {
- class CallExprWLItem {
- public:
- CallExpr::const_arg_iterator I;
- ExplodedNode *N;
- CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
- };
- }
- void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
- const FunctionProtoType *FnType,
- ExplodedNode *Pred, ExplodedNodeSet &Dst,
- bool FstArgAsLValue) {
- SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AI);
- WorkList.push_back(CallExprWLItem(AI, Pred));
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
- if (Item.I == AE) {
- Dst.insert(Item.N);
- continue;
- }
- // Evaluate the argument.
- ExplodedNodeSet Tmp;
- if (FstArgAsLValue) {
- FstArgAsLValue = false;
- }
- Visit(*Item.I, Item.N, Tmp);
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- }
- void ExprEngine::evalCallee(const CallExpr *callExpr,
- const ExplodedNodeSet &src,
- ExplodedNodeSet &dest) {
-
- const Expr *callee = 0;
-
- switch (callExpr->getStmtClass()) {
- case Stmt::CXXMemberCallExprClass: {
- // Evaluate the implicit object argument that is the recipient of the
- // call.
- callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
-
- // FIXME: handle member pointers.
- if (!callee)
- return;
- break;
- }
- default: {
- callee = callExpr->getCallee()->IgnoreParens();
- break;
- }
- }
- for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
- Visit(callee, *i, dest);
- }
- const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
- const StackFrameContext *SFC) {
- const Type *T = D->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T, 0));
- return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC);
- }
- const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
- const StackFrameContext *frameCtx) {
- return svalBuilder.getRegionManager().
- getCXXThisRegion(decl->getThisType(getContext()), frameCtx);
- }
- void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
- const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
- const ProgramState *state = Pred->getState();
- // Bind the temporary object to the value of the expression. Then bind
- // the expression to the location of the object.
- SVal V = state->getSVal(tempExpr);
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME,
- Pred->getLocationContext());
- state = state->bindLoc(loc::MemRegionVal(R), V);
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
- }
- void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
- const MemRegion *Dest,
- ExplodedNode *Pred,
- ExplodedNodeSet &destNodes) {
- const CXXConstructorDecl *CD = E->getConstructor();
- assert(CD);
-
- #if 0
- if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
- // FIXME: invalidate the object.
- return;
- #endif
-
- // Evaluate other arguments.
- ExplodedNodeSet argsEvaluated;
- const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
- evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
- #if 0
- // Is the constructor elidable?
- if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
- // FIXME: this is here to force propagation if VisitAggExpr doesn't
- if (destNodes.empty())
- destNodes.Add(Pred);
- return;
- }
- #endif
-
- // Perform the previsit of the constructor.
- ExplodedNodeSet destPreVisit;
- getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
- *this);
-
- // Evaluate the constructor. Currently we don't now allow checker-specific
- // implementations of specific constructors (as we do with ordinary
- // function calls. We can re-evaluate this in the future.
-
- #if 0
- // Inlining currently isn't fully implemented.
- if (AMgr.shouldInlineCall()) {
- if (!Dest)
- Dest =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
- Pred->getLocationContext());
- // The callee stack frame context used to create the 'this'
- // parameter region.
- const StackFrameContext *SFC =
- AMgr.getStackFrame(CD, Pred->getLocationContext(),
- E, currentBuilderContext->getBlock(),
- currentStmtIdx);
- // Create the 'this' region.
- const CXXThisRegion *ThisR =
- getCXXThisRegion(E->getConstructor()->getParent(), SFC);
- CallEnter Loc(E, SFC, Pred->getLocationContext());
- StmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext);
- for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
- NE = argsEvaluated.end(); NI != NE; ++NI) {
- const ProgramState *state = (*NI)->getState();
- // Setup 'this' region, so that the ctor is evaluated on the object pointed
- // by 'Dest'.
- state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- Bldr.generateNode(Loc, *NI, state);
- }
- }
- #endif
-
- // Default semantics: invalidate all regions passed as arguments.
- ExplodedNodeSet destCall;
- {
- StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext);
- for (ExplodedNodeSet::iterator
- i = destPreVisit.begin(), e = destPreVisit.end();
- i != e; ++i)
- {
- ExplodedNode *Pred = *i;
- const LocationContext *LC = Pred->getLocationContext();
- const ProgramState *state = Pred->getState();
- state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
- Bldr.generateNode(E, Pred, state);
- }
- }
- // Do the post visit.
- getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
- }
- void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
- const MemRegion *Dest,
- const Stmt *S,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
- if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
- return;
- // Create the context for 'this' region.
- const StackFrameContext *SFC =
- AnalysisDeclContexts.getContext(DD)->
- getStackFrame(Pred->getLocationContext(), S,
- currentBuilderContext->getBlock(), currentStmtIdx);
- const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
- CallEnter PP(S, SFC, Pred->getLocationContext());
- const ProgramState *state = Pred->getState();
- state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
- Bldr.generateNode(PP, Pred, state);
- }
- void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
-
- unsigned blockCount = currentBuilderContext->getCurrentBlockCount();
- DefinedOrUnknownSVal symVal =
- svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount);
- const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
- QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
- const ElementRegion *EleReg =
- getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
- if (CNE->isArray()) {
- // FIXME: allocating an array requires simulating the constructors.
- // For now, just return a symbolicated region.
- const ProgramState *state = Pred->getState();
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- Bldr.generateNode(CNE, Pred, state);
- return;
- }
- // Evaluate constructor arguments.
- const FunctionProtoType *FnType = NULL;
- const CXXConstructorDecl *CD = CNE->getConstructor();
- if (CD)
- FnType = CD->getType()->getAs<FunctionProtoType>();
- ExplodedNodeSet argsEvaluated;
- Bldr.takeNodes(Pred);
- evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
- FnType, Pred, argsEvaluated);
- Bldr.addNodes(argsEvaluated);
- // Initialize the object region and bind the 'new' expression.
- for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
- E = argsEvaluated.end(); I != E; ++I) {
- const ProgramState *state = (*I)->getState();
-
- // Accumulate list of regions that are invalidated.
- // FIXME: Eventually we should unify the logic for constructor
- // processing in one place.
- SmallVector<const MemRegion*, 10> regionsToInvalidate;
- for (CXXNewExpr::const_arg_iterator
- ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
- ai != ae; ++ai)
- {
- SVal val = state->getSVal(*ai);
- if (const MemRegion *region = val.getAsRegion())
- regionsToInvalidate.push_back(region);
- }
- if (ObjTy->isRecordType()) {
- regionsToInvalidate.push_back(EleReg);
- // Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
-
- } else {
- // Invalidate the regions.
- state = state->invalidateRegions(regionsToInvalidate,
- CNE, blockCount, 0,
- /* invalidateGlobals = */ true);
- if (CNE->hasInitializer()) {
- SVal V = state->getSVal(*CNE->constructor_arg_begin());
- state = state->bindLoc(loc::MemRegionVal(EleReg), V);
- } else {
- // Explicitly set to undefined, because currently we retrieve symbolic
- // value from symbolic region.
- state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
- }
- }
- state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
- Bldr.generateNode(CNE, *I, state);
- }
- }
- void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- // Should do more checking.
- ExplodedNodeSet Argevaluated;
- Visit(CDE->getArgument(), Pred, Argevaluated);
- StmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext);
- for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
- E = Argevaluated.end(); I != E; ++I) {
- const ProgramState *state = (*I)->getState();
- Bldr.generateNode(CDE, *I, state);
- }
- }
- void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
- // Get the this object region from StoreManager.
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXThisRegion(
- getContext().getCanonicalType(TE->getType()),
- Pred->getLocationContext());
- const ProgramState *state = Pred->getState();
- SVal V = state->getSVal(loc::MemRegionVal(R));
- Bldr.generateNode(TE, Pred, state->BindExpr(TE, V));
- }
|