[cfe-commits] r160809 - in /cfe/trunk: lib/StaticAnalyzer/Core/ExprEngineC.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp test/Analysis/dtor.cpp
Jordan Rose
jordan_rose at apple.com
Thu Jul 26 13:04:25 PDT 2012
Author: jrose
Date: Thu Jul 26 15:04:25 2012
New Revision: 160809
URL: http://llvm.org/viewvc/llvm-project?rev=160809&view=rev
Log:
[analyzer] Don't crash on array constructors and destructors.
This workaround is fairly lame: we simulate the first element's constructor
and destructor and rely on the region invalidation to "initialize" the rest
of the elements.
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
cfe/trunk/test/Analysis/dtor.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp?rev=160809&r1=160808&r2=160809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp Thu Jul 26 15:04:25 2012
@@ -453,16 +453,17 @@
const LocationContext *LC = N->getLocationContext();
if (const Expr *InitEx = VD->getInit()) {
- SVal InitVal = state->getSVal(InitEx, Pred->getLocationContext());
+ SVal InitVal = state->getSVal(InitEx, LC);
- if (InitVal == state->getLValue(VD, LC)) {
+ if (InitVal == state->getLValue(VD, LC) ||
+ (VD->getType()->isArrayType() &&
+ isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
// We constructed the object directly in the variable.
// No need to bind anything.
B.generateNode(DS, N, state);
} else {
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
- // FIXME: This is probably not correct for most constructors!
if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
!VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160809&r1=160808&r2=160809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Jul 26 15:04:25 2012
@@ -57,12 +57,27 @@
CFGElement Next = (*B)[currentStmtIdx+1];
// Is this a constructor for a local variable?
- if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next))
- if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt()))
- if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl()))
- if (Var->getInit() == CE)
- Target = State->getLValue(Var, LCtx).getAsRegion();
-
+ if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) {
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) {
+ if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
+ if (Var->getInit()->IgnoreImplicit() == CE) {
+ QualType Ty = Var->getType();
+ if (const ArrayType *AT = getContext().getAsArrayType(Ty)) {
+ // FIXME: Handle arrays, which run the same constructor for
+ // every element. This workaround will just run the first
+ // constructor (which should still invalidate the entire array).
+ SVal Base = State->getLValue(Var, LCtx);
+ Target = State->getLValue(AT->getElementType(),
+ getSValBuilder().makeZeroArrayIndex(),
+ Base).getAsRegion();
+ } else {
+ 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();
@@ -75,10 +90,10 @@
if (Init->isIndirectMemberInitializer()) {
SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal);
- Target = cast<loc::MemRegionVal>(Field).getRegion();
+ Target = Field.getAsRegion();
} else {
SVal Field = State->getLValue(Init->getMember(), ThisVal);
- Target = cast<loc::MemRegionVal>(Field).getRegion();
+ Target = Field.getAsRegion();
}
}
@@ -104,7 +119,7 @@
// Cast to the base type.
QualType BaseTy = CE->getType();
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
- Target = cast<loc::MemRegionVal>(BaseVal).getRegion();
+ Target = BaseVal.getAsRegion();
}
break;
}
@@ -135,6 +150,16 @@
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ // FIXME: We need to run the same destructor on every element of the array.
+ // This workaround will just run the first destructor (which will still
+ // invalidate the entire array).
+ if (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) {
+ ObjectType = AT->getElementType();
+ Dest = Pred->getState()->getLValue(ObjectType,
+ getSValBuilder().makeZeroArrayIndex(),
+ loc::MemRegionVal(Dest)).getAsRegion();
+ }
+
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160809&r1=160808&r2=160809&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Thu Jul 26 15:04:25 2012
@@ -306,14 +306,18 @@
!ADC->getCFGBuildOptions().AddInitializers)
return false;
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ const MemRegion *Target = Call.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return false;
+
// 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 (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
- if (!isa<DeclRegion>(Target))
- return false;
+ if (!Target || !isa<DeclRegion>(Target))
+ return false;
}
break;
}
@@ -461,6 +465,8 @@
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.
Modified: cfe/trunk/test/Analysis/dtor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dtor.cpp?rev=160809&r1=160808&r2=160809&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dtor.cpp (original)
+++ cfe/trunk/test/Analysis/dtor.cpp Thu Jul 26 15:04:25 2012
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -cfg-add-initializers -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -cfg-add-initializers -verify %s
+
+void clang_analyzer_eval(bool);
class A {
public:
@@ -100,7 +102,7 @@
// Remove dead bindings...
doSomething();
// destructor called here
- // expected-warning at 25 {{Attempt to free released memory}}
+ // expected-warning at 27 {{Attempt to free released memory}}
}
}
@@ -121,3 +123,34 @@
}
*mem = 0; // expected-warning{{Use of memory after it is freed}}
}
+
+
+struct IntWrapper {
+ IntWrapper() : x(0) {}
+ ~IntWrapper();
+ int *x;
+};
+
+void testArrayInvalidation() {
+ int i = 42;
+ int j = 42;
+
+ {
+ IntWrapper arr[2];
+
+ // There should be no undefined value warnings here.
+ // Eventually these should be TRUE as well, but right now
+ // we can't handle array constructors.
+ clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
+
+ arr[0].x = &i;
+ arr[1].x = &j;
+ clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
+ }
+
+ // The destructors should have invalidated i and j.
+ clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
+}
More information about the cfe-commits
mailing list