diff options
author | dim <dim@FreeBSD.org> | 2011-10-20 21:14:49 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-10-20 21:14:49 +0000 |
commit | 3963a48221351c61c17fb3f382341ab04809a3d3 (patch) | |
tree | ee2483e98b09cac943dc93a6969d83ca737ff139 /lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | |
parent | 611ba3ea3300b71eb95dc4e45f20eee5dddd32e1 (diff) | |
download | FreeBSD-src-3963a48221351c61c17fb3f382341ab04809a3d3.zip FreeBSD-src-3963a48221351c61c17fb3f382341ab04809a3d3.tar.gz |
Vendor import of clang release_30 branch r142614:
http://llvm.org/svn/llvm-project/cfe/branches/release_30@142614
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp new file mode 100644 index 0000000..acb0074 --- /dev/null +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -0,0 +1,339 @@ +//===- 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) { + 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); + MakeNode(Dst, 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, Builder->getBlock(), Builder->getIndex()); + + // Create the 'this' region. + const CXXThisRegion *ThisR = + getCXXThisRegion(E->getConstructor()->getParent(), SFC); + + CallEnter Loc(E, SFC, Pred->getLocationContext()); + + + 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)); + if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI)) + destNodes.Add(N); + } + } +#endif + + // Default semantics: invalidate all regions passed as arguments. + ExplodedNodeSet destCall; + + 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); + Builder->MakeNode(destCall, 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) { + if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) + return; + // Create the context for 'this' region. + const StackFrameContext *SFC = AMgr.getStackFrame(DD, + Pred->getLocationContext(), + S, Builder->getBlock(), + Builder->getIndex()); + + 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)); + ExplodedNode *N = Builder->generateNode(PP, state, Pred); + if (N) + Dst.Add(N); +} + +void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + unsigned blockCount = Builder->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)); + MakeNode(Dst, 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; + evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), + FnType, Pred, 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)); + MakeNode(Dst, CNE, *I, state); + } +} + +void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, + ExplodedNode *Pred,ExplodedNodeSet &Dst) { + // Should do more checking. + ExplodedNodeSet Argevaluated; + Visit(CDE->getArgument(), Pred, Argevaluated); + for (ExplodedNodeSet::iterator I = Argevaluated.begin(), + E = Argevaluated.end(); I != E; ++I) { + const ProgramState *state = (*I)->getState(); + MakeNode(Dst, CDE, *I, state); + } +} + +void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // 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)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); +} |