[cfe-commits] r160808 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp test/Analysis/dtor.cpp test/Analysis/initializer.cpp
Jordan Rose
jordan_rose at apple.com
Thu Jul 26 13:04:22 PDT 2012
Author: jrose
Date: Thu Jul 26 15:04:21 2012
New Revision: 160808
URL: http://llvm.org/viewvc/llvm-project?rev=160808&view=rev
Log:
[analyzer] Handle C++ member initializers and destructors.
This uses CFG to tell if a constructor call is for a member, and uses
the member's region appropriately.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
cfe/trunk/test/Analysis/dtor.cpp
cfe/trunk/test/Analysis/initializer.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h Thu Jul 26 15:04:21 2012
@@ -238,6 +238,9 @@
/// Get the lvalue for a field reference.
SVal getLValue(const FieldDecl *decl, SVal Base) const;
+ /// Get the lvalue for an indirect field reference.
+ SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const;
+
/// Get the lvalue for an array index.
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
@@ -649,6 +652,18 @@
return getStateManager().StoreMgr->getLValueField(D, Base);
}
+inline SVal ProgramState::getLValue(const IndirectFieldDecl *D,
+ SVal Base) const {
+ StoreManager &SM = *getStateManager().StoreMgr;
+ for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
+ E = D->chain_end();
+ I != E; ++I) {
+ Base = SM.getLValueField(cast<FieldDecl>(*I), Base);
+ }
+
+ return Base;
+}
+
inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Jul 26 15:04:21 2012
@@ -358,43 +358,42 @@
ExplodedNodeSet Dst;
NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+ ProgramStateRef State = Pred->getState();
+
// We don't set EntryNode and currentStmt. And we don't clean up state.
const CXXCtorInitializer *BMI = Init.getInitializer();
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
cast<CXXConstructorDecl>(stackFrame->getDecl());
- SVal thisVal = Pred->getState()->getSVal(svalBuilder.getCXXThis(decl,
- stackFrame));
+ SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
+ // Evaluate the initializer, if necessary
if (BMI->isAnyMemberInitializer()) {
- // Evaluate the initializer.
- ProgramStateRef state = Pred->getState();
-
- const FieldDecl *FD = BMI->getAnyMember();
+ // Constructors build the object directly in the field,
+ // but non-objects must be copied in from the initializer.
+ if (!isa<CXXConstructExpr>(BMI->getInit())) {
+ SVal FieldLoc;
+ if (BMI->isIndirectMemberInitializer())
+ FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
+ else
+ FieldLoc = State->getLValue(BMI->getMember(), thisVal);
- // FIXME: This does not work for initializers that call constructors.
- SVal FieldLoc = state->getLValue(FD, thisVal);
- SVal InitVal = state->getSVal(BMI->getInit(), Pred->getLocationContext());
- state = state->bindLoc(FieldLoc, InitVal);
-
- // Use a custom node building process.
- 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, state, Pred);
+ SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
+ State = State->bindLoc(FieldLoc, InitVal);
+ }
} else {
assert(BMI->isBaseInitializer());
-
// 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);
}
+ // Construct a PostInitializer node whether the state changed or not,
+ // 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, State, Pred);
+
// Enqueue the new nodes onto the work list.
Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx);
}
@@ -459,7 +458,20 @@
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {}
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ const FieldDecl *Member = D.getFieldDecl();
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
+ Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
+ LCtx->getCurrentStackFrame());
+ SVal FieldVal = State->getLValue(Member, cast<Loc>(State->getSVal(ThisVal)));
+
+ VisitCXXDestructor(Member->getType(),
+ cast<loc::MemRegionVal>(FieldVal).getRegion(),
+ CurDtor->getBody(), Pred, Dst);
+}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
ExplodedNode *Pred,
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Jul 26 15:04:21 2012
@@ -63,6 +63,25 @@
if (Var->getInit() == CE)
Target = State->getLValue(Var, LCtx).getAsRegion();
+ // Is this a constructor for a member?
+ if (const CFGInitializer *InitElem = dyn_cast<CFGInitializer>(&Next)) {
+ const CXXCtorInitializer *Init = InitElem->getInitializer();
+ assert(Init->isAnyMemberInitializer());
+
+ const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
+ Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
+ LCtx->getCurrentStackFrame());
+ SVal ThisVal = State->getSVal(ThisPtr);
+
+ if (Init->isIndirectMemberInitializer()) {
+ SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal);
+ Target = cast<loc::MemRegionVal>(Field).getRegion();
+ } else {
+ SVal Field = State->getLValue(Init->getMember(), ThisVal);
+ Target = cast<loc::MemRegionVal>(Field).getRegion();
+ }
+ }
+
// FIXME: This will eventually need to handle new-expressions as well.
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Thu Jul 26 15:04:21 2012
@@ -305,13 +305,15 @@
if (!ADC->getCFGBuildOptions().AddImplicitDtors ||
!ADC->getCFGBuildOptions().AddInitializers)
return false;
- // FIXME: This is a hack. We don't handle member or temporary constructors
+
+ // FIXME: This is a hack. We don't handle temporary destructors
// 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;
+ if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
+ if (!isa<DeclRegion>(Target))
+ return false;
}
break;
}
Modified: cfe/trunk/test/Analysis/dtor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dtor.cpp?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dtor.cpp (original)
+++ cfe/trunk/test/Analysis/dtor.cpp Thu Jul 26 15:04:21 2012
@@ -103,3 +103,21 @@
// expected-warning at 25 {{Attempt to free released memory}}
}
}
+
+
+class SmartPointerMember {
+ SmartPointer P;
+public:
+ SmartPointerMember(void *x) : P(x) {}
+};
+
+void testSmartPointerMember() {
+ char *mem = (char*)malloc(4);
+ {
+ SmartPointerMember Deleter(mem);
+ // Remove dead bindings...
+ doSomething();
+ // destructor called here
+ }
+ *mem = 0; // expected-warning{{Use of memory after it is freed}}
+}
Modified: cfe/trunk/test/Analysis/initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/initializer.cpp?rev=160808&r1=160807&r2=160808&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/initializer.cpp (original)
+++ cfe/trunk/test/Analysis/initializer.cpp Thu Jul 26 15:04:21 2012
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -cfg-add-initializers -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store region -cfg-add-initializers -cfg-add-implicit-dtors -verify %s
+
+// We don't inline constructors unless we have both initializers and
+// implicit destructors turned on.
void clang_analyzer_eval(bool);
@@ -11,3 +14,33 @@
A::A() : x(0) {
clang_analyzer_eval(x == 0); // expected-warning{{TRUE}}
}
+
+
+class DirectMember {
+ int x;
+public:
+ DirectMember(int value) : x(value) {}
+
+ int getX() { return x; }
+};
+
+void testDirectMember() {
+ DirectMember obj(3);
+ clang_analyzer_eval(obj.getX() == 3); // expected-warning{{TRUE}}
+}
+
+
+class IndirectMember {
+ struct {
+ int x;
+ };
+public:
+ IndirectMember(int value) : x(value) {}
+
+ int getX() { return x; }
+};
+
+void testIndirectMember() {
+ IndirectMember obj(3);
+ clang_analyzer_eval(obj.getX() == 3); // expected-warning{{TRUE}}
+}
More information about the cfe-commits
mailing list