mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-03 19:32:35 +00:00
[analyzer] For now, treat pointers-to-members as non-null void * symbols.
Until we have full support for pointers-to-members, we can at least approximate some of their use by tracking null and non-null values. We thus treat &A::m_ptr as a non-null void * symbol, and MemberPointer(0) as a pointer-sized null constant. This enables support for what is sometimes called the "safe bool" idiom, demonstrated in the test case. llvm-svn: 162495
This commit is contained in:
parent
081af085eb
commit
434f132060
@ -1428,7 +1428,12 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
|
||||
}
|
||||
if (isa<FieldDecl>(D)) {
|
||||
// FIXME: Compute lvalue of field pointers-to-member.
|
||||
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()), 0,
|
||||
// Right now we just use a non-null void pointer, so that it gives proper
|
||||
// results in boolean contexts.
|
||||
SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
|
||||
currBldrCtx->blockCount());
|
||||
state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
|
||||
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
|
||||
ProgramPoint::PostLValueKind);
|
||||
return;
|
||||
}
|
||||
|
@ -274,6 +274,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_MemberPointerToBoolean:
|
||||
// FIXME: For now, member pointers are represented by void *.
|
||||
// FALLTHROUGH
|
||||
case CK_Dependent:
|
||||
case CK_ArrayToPointerDecay:
|
||||
case CK_BitCast:
|
||||
@ -359,16 +362,21 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_NullToMemberPointer: {
|
||||
// FIXME: For now, member pointers are represented by void *.
|
||||
SVal V = svalBuilder.makeIntValWithPtrWidth(0, true);
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
// Various C++ casts that are not handled yet.
|
||||
case CK_ToUnion:
|
||||
case CK_BaseToDerived:
|
||||
case CK_NullToMemberPointer:
|
||||
case CK_BaseToDerivedMemberPointer:
|
||||
case CK_DerivedToBaseMemberPointer:
|
||||
case CK_ReinterpretMemberPointer:
|
||||
case CK_ConstructorConversion:
|
||||
case CK_VectorSplat:
|
||||
case CK_MemberPointerToBoolean:
|
||||
case CK_LValueBitCast: {
|
||||
// Recover some path-sensitivty by conjuring a new value.
|
||||
QualType resultType = CastE->getType();
|
||||
|
44
clang/test/Analysis/pointer-to-member.cpp
Normal file
44
clang/test/Analysis/pointer-to-member.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
|
||||
|
||||
void clang_analyzer_eval(bool);
|
||||
|
||||
struct A {
|
||||
// This conversion operator allows implicit conversion to bool but not to other integer types.
|
||||
typedef A * (A::*MemberPointer);
|
||||
operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; }
|
||||
|
||||
A *m_ptr;
|
||||
};
|
||||
|
||||
void testConditionalUse() {
|
||||
A obj;
|
||||
|
||||
obj.m_ptr = &obj;
|
||||
clang_analyzer_eval(obj.m_ptr); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(&A::m_ptr); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(obj); // expected-warning{{TRUE}}
|
||||
|
||||
obj.m_ptr = 0;
|
||||
clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}}
|
||||
clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}}
|
||||
clang_analyzer_eval(obj); // expected-warning{{FALSE}}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// FALSE NEGATIVES
|
||||
// ---------------
|
||||
|
||||
bool testDereferencing() {
|
||||
A obj;
|
||||
obj.m_ptr = 0;
|
||||
|
||||
A::MemberPointer member = &A::m_ptr;
|
||||
|
||||
// FIXME: Should be TRUE.
|
||||
clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
|
||||
|
||||
member = 0;
|
||||
|
||||
// FIXME: Should emit a null dereference.
|
||||
return obj.*member; // no-warning
|
||||
}
|
Loading…
Reference in New Issue
Block a user