Skip to content

Commit 44583ce

Browse files
committedAug 8, 2016
[analyzer] Model base to derived casts more precisely.
Dynamic casts are handled relatively well by the static analyzer. BaseToDerived casts however are treated conservatively. This can cause some false positives with the NewDeleteLeaks checker. This patch alters the behavior of BaseToDerived casts. In case a dynamic cast would succeed use the same semantics. Otherwise fall back to the conservative approach. Differential Revision: https://reviews.llvm.org/D23014 llvm-svn: 277989
1 parent 2ab623b commit 44583ce

File tree

5 files changed

+46
-6
lines changed

5 files changed

+46
-6
lines changed
 

‎clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,18 @@ class StoreManager {
123123
SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
124124
bool IsVirtual);
125125

126-
/// \brief Evaluates C++ dynamic_cast cast.
126+
/// \brief Attempts to do a down cast. Used to model BaseToDerived and C++
127+
/// dynamic_cast.
127128
/// The callback may result in the following 3 scenarios:
128129
/// - Successful cast (ex: derived is subclass of base).
129130
/// - Failed cast (ex: derived is definitely not a subclass of base).
131+
/// The distinction of this case from the next one is necessary to model
132+
/// dynamic_cast.
130133
/// - We don't know (base is a symbolic region and we don't have
131134
/// enough info to determine if the cast will succeed at run time).
132135
/// The function returns an SVal representing the derived class; it's
133136
/// valid only if Failed flag is set to false.
134-
SVal evalDynamicCast(SVal Base, QualType DerivedPtrType, bool &Failed);
137+
SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed);
135138

136139
const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
137140

‎clang/lib/StaticAnalyzer/Core/CallEvent.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void CXXInstanceCall::getInitialStackFrameContents(
552552

553553
// FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
554554
bool Failed;
555-
ThisVal = StateMgr.getStoreManager().evalDynamicCast(ThisVal, Ty, Failed);
555+
ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, Failed);
556556
assert(!Failed && "Calling an incorrectly devirtualized method");
557557
}
558558

‎clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
386386
Failed = true;
387387
// Else, evaluate the cast.
388388
else
389-
val = getStoreManager().evalDynamicCast(val, T, Failed);
389+
val = getStoreManager().attemptDownCast(val, T, Failed);
390390

391391
if (Failed) {
392392
if (T->isReferenceType()) {
@@ -412,6 +412,28 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
412412
Bldr.generateNode(CastE, Pred, state);
413413
continue;
414414
}
415+
case CK_BaseToDerived: {
416+
SVal val = state->getSVal(Ex, LCtx);
417+
QualType resultType = CastE->getType();
418+
if (CastE->isGLValue())
419+
resultType = getContext().getPointerType(resultType);
420+
421+
bool Failed = false;
422+
423+
if (!val.isConstant()) {
424+
val = getStoreManager().attemptDownCast(val, T, Failed);
425+
}
426+
427+
// Failed to cast or the result is unknown, fall back to conservative.
428+
if (Failed || val.isUnknown()) {
429+
val =
430+
svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
431+
currBldrCtx->blockCount());
432+
}
433+
state = state->BindExpr(CastE, LCtx, val);
434+
Bldr.generateNode(CastE, Pred, state);
435+
continue;
436+
}
415437
case CK_NullToMemberPointer: {
416438
// FIXME: For now, member pointers are represented by void *.
417439
SVal V = svalBuilder.makeNull();
@@ -421,7 +443,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
421443
}
422444
// Various C++ casts that are not handled yet.
423445
case CK_ToUnion:
424-
case CK_BaseToDerived:
425446
case CK_BaseToDerivedMemberPointer:
426447
case CK_DerivedToBaseMemberPointer:
427448
case CK_ReinterpretMemberPointer:

‎clang/lib/StaticAnalyzer/Core/Store.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) {
292292
return nullptr;
293293
}
294294

295-
SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType,
295+
SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType,
296296
bool &Failed) {
297297
Failed = false;
298298

‎clang/test/Analysis/NewDelete-checker-test.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,19 @@ void testDoubleDeleteEmptyClass() {
377377
delete foo;
378378
delete foo; // expected-warning {{Attempt to delete released memory}}
379379
}
380+
381+
struct Base {
382+
virtual ~Base() {}
383+
};
384+
385+
struct Derived : Base {
386+
};
387+
388+
Base *allocate() {
389+
return new Derived;
390+
}
391+
392+
void shouldNotReportLeak() {
393+
Derived *p = (Derived *)allocate();
394+
delete p;
395+
}

0 commit comments

Comments
 (0)
Please sign in to comment.