[cfe-commits] r160806 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp lib/StaticAnalyzer/Core/PathDiagnostic.cpp
Jordan Rose
jordan_rose at apple.com
Thu Jul 26 13:04:13 PDT 2012
Author: jrose
Date: Thu Jul 26 15:04:13 2012
New Revision: 160806
URL: http://llvm.org/viewvc/llvm-project?rev=160806&view=rev
Log:
[analyzer] Handle base class initializers and destructors.
Most of the logic here is fairly simple; the interesting thing is that
we now distinguish complete constructors from base or delegate constructors.
We also make sure to cast to the base class before evaluating a constructor
or destructor, since non-virtual base classes may behave differently.
This includes some refactoring of VisitCXXConstructExpr and VisitCXXDestructor
in order to keep ExprEngine.cpp as clean as possible (leaving the details for
ExprEngineCXX.cpp).
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=160806&r1=160805&r2=160806&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Thu Jul 26 15:04:13 2012
@@ -378,10 +378,10 @@
void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
- void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
- void VisitCXXDestructor(const CXXDestructorDecl *DD,
+ void VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest, const Stmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=160806&r1=160805&r2=160806&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Jul 26 15:04:13 2012
@@ -24,7 +24,6 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/DeclCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
@@ -357,6 +356,7 @@
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ExplodedNode *Pred) {
ExplodedNodeSet Dst;
+ NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
// We don't set EntryNode and currentStmt. And we don't clean up state.
const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -369,8 +369,6 @@
if (BMI->isAnyMemberInitializer()) {
// Evaluate the initializer.
-
- StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
ProgramStateRef state = Pred->getState();
const FieldDecl *FD = BMI->getAnyMember();
@@ -384,20 +382,17 @@
PostInitializer PP(BMI, stackFrame);
// Builder automatically add the generated node to the deferred set,
// which are processed in the builder's dtor.
- Bldr.generateNode(PP, Pred, state);
+ Bldr.generateNode(PP, state, Pred);
} else {
assert(BMI->isBaseInitializer());
- // Get the base class declaration.
- const CXXConstructExpr *ctorExpr = cast<CXXConstructExpr>(BMI->getInit());
-
- // Create the base object region.
- SVal baseVal =
- getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
- const MemRegion *baseReg = baseVal.getAsRegion();
- assert(baseReg);
-
- VisitCXXConstructExpr(ctorExpr, baseReg, Pred, Dst);
+ // We already did all the work when visiting the CXXConstructExpr.
+ // Just construct a PostInitializer node so that the diagnostics don't get
+ // confused.
+ PostInitializer PP(BMI, stackFrame);
+ // Builder automatically add the generated node to the deferred set,
+ // which are processed in the builder's dtor.
+ Bldr.generateNode(PP, Pred->getState(), Pred);
}
// Enqueue the new nodes onto the work list.
@@ -439,18 +434,29 @@
if (const ReferenceType *refType = varType->getAs<ReferenceType>())
varType = refType->getPointeeType();
- const CXXRecordDecl *recordDecl = varType->getAsCXXRecordDecl();
- assert(recordDecl && "get CXXRecordDecl fail");
- const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor();
-
Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
- VisitCXXDestructor(dtorDecl, cast<loc::MemRegionVal>(dest).getRegion(),
+ VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
Dtor.getTriggerStmt(), Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {}
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef State = Pred->getState();
+
+ const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
+ Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor,
+ LCtx->getCurrentStackFrame());
+ SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
+
+ // Create the base object region.
+ QualType BaseTy = D.getBaseSpecifier()->getType();
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+
+ VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
+ CurDtor->getBody(), Pred, Dst);
+}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {}
@@ -459,26 +465,6 @@
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {}
-static const VarDecl *findDirectConstruction(const DeclStmt *DS,
- const Expr *Init) {
- for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
- I != E; ++I) {
- const VarDecl *Var = dyn_cast<VarDecl>(*I);
- if (!Var)
- continue;
- if (Var->getInit() != Init)
- continue;
- // FIXME: We need to decide how copy-elision should work here.
- if (!Var->isDirectInit())
- break;
- if (Var->getType()->isReferenceType())
- break;
- return Var;
- }
-
- return 0;
-}
-
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet &DstTop) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@@ -739,20 +725,9 @@
}
case Stmt::CXXTemporaryObjectExprClass:
- case Stmt::CXXConstructExprClass: {
- const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
- const MemRegion *Target = 0;
-
- const LocationContext *LCtx = Pred->getLocationContext();
- const ParentMap &PM = LCtx->getParentMap();
- if (const DeclStmt *DS = dyn_cast_or_null<DeclStmt>(PM.getParent(C)))
- if (const VarDecl *Var = findDirectConstruction(DS, C))
- Target = Pred->getState()->getLValue(Var, LCtx).getAsRegion();
- // If we don't have a destination region, VisitCXXConstructExpr() will
- // create one.
-
+ case Stmt::CXXConstructExprClass: {
Bldr.takeNodes(Pred);
- VisitCXXConstructExpr(C, Target, Pred, Dst);
+ VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160806&r1=160805&r2=160806&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Jul 26 15:04:13 2012
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/ParentMap.h"
using namespace clang;
using namespace ento;
@@ -40,11 +41,68 @@
Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
}
+static const VarDecl *findDirectConstruction(const DeclStmt *DS,
+ const Expr *Init) {
+ for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
+ I != E; ++I) {
+ const VarDecl *Var = dyn_cast<VarDecl>(*I);
+ if (!Var)
+ continue;
+ if (Var->getInit() != Init)
+ continue;
+ // FIXME: We need to decide how copy-elision should work here.
+ if (!Var->isDirectInit())
+ break;
+ if (Var->getType()->isReferenceType())
+ break;
+ return Var;
+ }
+
+ return 0;
+}
+
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
- const MemRegion *Dest,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
- CXXConstructorCall Call(CE, Dest, Pred->getState(),
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const MemRegion *Target = 0;
+
+ switch (CE->getConstructionKind()) {
+ case CXXConstructExpr::CK_Complete: {
+ // See if we're constructing an existing region.
+ // FIXME: This is inefficient. Not only are we getting the parent of the
+ // CXXConstructExpr, but we also then have to crawl through it if it's a
+ // DeclStmt to find out which variable is being constructed. (The CFG has
+ // one (fake) DeclStmt per Decl, but ParentMap uses the original AST.)
+ const ParentMap &PM = LCtx->getParentMap();
+ if (const DeclStmt *DS = dyn_cast_or_null<DeclStmt>(PM.getParent(CE)))
+ if (const VarDecl *Var = findDirectConstruction(DS, CE))
+ Target = Pred->getState()->getLValue(Var, LCtx).getAsRegion();
+ // If we can't find an existing region to construct into, we'll just
+ // generate a symbolic region, which is fine.
+ break;
+ }
+ case CXXConstructExpr::CK_NonVirtualBase:
+ case CXXConstructExpr::CK_VirtualBase:
+ case CXXConstructExpr::CK_Delegating: {
+ const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
+ Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
+ LCtx->getCurrentStackFrame());
+ SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
+
+ if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) {
+ Target = ThisVal.getAsRegion();
+ } else {
+ // Cast to the base type.
+ QualType BaseTy = CE->getType();
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+ Target = cast<loc::MemRegionVal>(BaseVal).getRegion();
+ }
+ break;
+ }
+ }
+
+ CXXConstructorCall Call(CE, Target, Pred->getState(),
Pred->getLocationContext());
ExplodedNodeSet DstPreVisit;
@@ -65,12 +123,16 @@
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
}
-void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
- const MemRegion *Dest,
- const Stmt *S,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- CXXDestructorCall Call(DD, S, Dest, Pred->getState(),
+void ExprEngine::VisitCXXDestructor(QualType ObjectType,
+ const MemRegion *Dest,
+ const Stmt *S,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
+ assert(RecordDecl && "Only CXXRecordDecls should have destructors");
+ const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
+
+ CXXDestructorCall Call(DtorDecl, S, Dest, Pred->getState(),
Pred->getLocationContext());
ExplodedNodeSet DstPreCall;
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160806&r1=160805&r2=160806&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Thu Jul 26 15:04:13 2012
@@ -70,37 +70,49 @@
static std::pair<const Stmt*,
const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
const Stmt *S = 0;
- const CFGBlock *Blk = 0;
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
+
+ // Back up through the ExplodedGraph until we reach a statement node.
while (Node) {
const ProgramPoint &PP = Node->getLocation();
- // Skip any BlockEdges, empty blocks, and the CallExitBegin node.
- if (isa<BlockEdge>(PP) || isa<CallExitBegin>(PP) || isa<BlockEntrance>(PP)){
- assert(Node->pred_size() == 1);
- Node = *Node->pred_begin();
- continue;
- }
- // If we reached the CallEnter, the function has no statements.
- if (isa<CallEnter>(PP))
- break;
+
if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
S = SP->getStmt();
- // Now, get the enclosing basic block.
- while (Node && Node->pred_size() >=1 ) {
- const ProgramPoint &PP = Node->getLocation();
- if (isa<BlockEdge>(PP) &&
- (PP.getLocationContext()->getCurrentStackFrame() == SF)) {
- BlockEdge &EPP = cast<BlockEdge>(PP);
- Blk = EPP.getDst();
- break;
- }
- Node = *Node->pred_begin();
- }
break;
+ } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
+ S = CEE->getCalleeContext()->getCallSite();
+ if (S)
+ break;
+ // If we have an implicit call, we'll probably end up with a
+ // StmtPoint inside the callee, which is acceptable.
+ // (It's possible a function ONLY contains implicit calls -- such as an
+ // implicitly-generated destructor -- so we shouldn't just skip back to
+ // the CallEnter node and keep going.)
+ } else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) {
+ // If we reached the CallEnter for this function, it has no statements.
+ if (CE->getCalleeContext() == SF)
+ break;
}
- break;
+
+ Node = *Node->pred_begin();
}
+
+ const CFGBlock *Blk = 0;
+ if (S) {
+ // Now, get the enclosing basic block.
+ while (Node && Node->pred_size() >=1 ) {
+ const ProgramPoint &PP = Node->getLocation();
+ if (isa<BlockEdge>(PP) &&
+ (PP.getLocationContext()->getCurrentStackFrame() == SF)) {
+ BlockEdge &EPP = cast<BlockEdge>(PP);
+ Blk = EPP.getDst();
+ break;
+ }
+ Node = *Node->pred_begin();
+ }
+ }
+
return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
}
@@ -293,11 +305,14 @@
if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
!ADC->getCFGBuildOptions().AddInitializers)
return false;
- // FIXME: This is a hack. We only process VarDecl destructors right now,
- // so we should only inline VarDecl constructors.
- if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call))
- if (!isa<VarRegion>(Ctor->getCXXThisVal().getAsRegion()))
- return false;
+ // FIXME: This is a hack. We don't handle member or temporary constructors
+ // right now, so we shouldn't inline their constructors.
+ if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
+ const CXXConstructExpr *CtorExpr = Ctor->getOriginExpr();
+ if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ if (!isa<VarRegion>(Ctor->getCXXThisVal().getAsRegion()))
+ return false;
+ }
break;
}
case CE_CXXAllocator:
Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=160806&r1=160805&r2=160806&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Thu Jul 26 15:04:13 2012
@@ -532,7 +532,12 @@
SM, CallerCtx);
}
case CFGElement::BaseDtor:
- case CFGElement::MemberDtor:
+ case CFGElement::MemberDtor: {
+ const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
+ if (const Stmt *CallerBody = CallerInfo->getBody())
+ return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
+ return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
+ }
case CFGElement::TemporaryDtor:
llvm_unreachable("not yet implemented!");
}
More information about the cfe-commits
mailing list