forked from OSchip/llvm-project
C++ static analysis: also invalidate fields of objects that are the callees in C++ method calls.
llvm-svn: 129308
This commit is contained in:
parent
0f85789800
commit
8ef59e5c03
|
@ -171,14 +171,23 @@ class CallOrObjCMessage {
|
|||
const CallExpr *CallE;
|
||||
ObjCMessage Msg;
|
||||
const GRState *State;
|
||||
|
||||
public:
|
||||
CallOrObjCMessage(const CallExpr *callE, const GRState *state)
|
||||
: CallE(callE), State(state) { }
|
||||
: CallE(callE), State(state) {}
|
||||
CallOrObjCMessage(const ObjCMessage &msg, const GRState *state)
|
||||
: CallE(0), Msg(msg), State(state) { }
|
||||
: CallE(0), Msg(msg), State(state) {}
|
||||
|
||||
QualType getResultType(ASTContext &ctx) const;
|
||||
|
||||
bool isFunctionCall() const {
|
||||
return (bool) CallE;
|
||||
}
|
||||
|
||||
bool isCXXCall() const {
|
||||
return CallE && isa<CXXMemberCallExpr>(CallE);
|
||||
}
|
||||
|
||||
SVal getCXXCallee() const;
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
if (CallE) return CallE->getNumArgs();
|
||||
|
@ -187,7 +196,8 @@ public:
|
|||
|
||||
SVal getArgSVal(unsigned i) const {
|
||||
assert(i < getNumArgs());
|
||||
if (CallE) return State->getSVal(CallE->getArg(i));
|
||||
if (CallE)
|
||||
return State->getSVal(CallE->getArg(i));
|
||||
return Msg.getArgSVal(i, State);
|
||||
}
|
||||
|
||||
|
@ -195,13 +205,15 @@ public:
|
|||
|
||||
const Expr *getArg(unsigned i) const {
|
||||
assert(i < getNumArgs());
|
||||
if (CallE) return CallE->getArg(i);
|
||||
if (CallE)
|
||||
return CallE->getArg(i);
|
||||
return Msg.getArgExpr(i);
|
||||
}
|
||||
|
||||
SourceRange getArgSourceRange(unsigned i) const {
|
||||
assert(i < getNumArgs());
|
||||
if (CallE) return CallE->getArg(i)->getSourceRange();
|
||||
if (CallE)
|
||||
return CallE->getArg(i)->getSourceRange();
|
||||
return Msg.getArgSourceRange(i);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2529,6 +2529,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
|
|||
RegionsToInvalidate.push_back(region);
|
||||
}
|
||||
|
||||
// Invalidate all instance variables for the callee of a C++ method call.
|
||||
// FIXME: We should be able to do better with inter-procedural analysis.
|
||||
// FIXME: we can probably do better for const versus non-const methods.
|
||||
if (callOrMsg.isCXXCall()) {
|
||||
if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion())
|
||||
RegionsToInvalidate.push_back(callee);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
|
||||
SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
|
||||
SymbolRef Sym = V.getAsLocSymbol();
|
||||
|
|
|
@ -111,7 +111,7 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const {
|
|||
QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const {
|
||||
QualType resultTy;
|
||||
bool isLVal = false;
|
||||
|
||||
|
||||
if (CallE) {
|
||||
isLVal = CallE->isLValue();
|
||||
const Expr *Callee = CallE->getCallee();
|
||||
|
@ -140,3 +140,10 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
|
|||
return Msg.getArgSVal(i, State);
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
SVal CallOrObjCMessage::getCXXCallee() const {
|
||||
assert(isCXXCall());
|
||||
const Expr *callee =
|
||||
cast<CXXMemberCallExpr>(CallE)->getImplicitObjectArgument();
|
||||
return State->getSVal(callee);
|
||||
}
|
||||
|
|
|
@ -303,3 +303,36 @@ void PR9645() {
|
|||
|
||||
PR9645_SideEffect::PR9645_SideEffect(int *pi) : i_(pi) {}
|
||||
void PR9645_SideEffect::Read(int *pi) { *i_ = *pi; }
|
||||
|
||||
// Invalidate fields during C++ method calls.
|
||||
class RDar9267815 {
|
||||
int x;
|
||||
void test();
|
||||
void test_pos();
|
||||
void test2();
|
||||
void invalidate();
|
||||
};
|
||||
|
||||
void RDar9267815::test_pos() {
|
||||
int *p = 0;
|
||||
if (x == 42)
|
||||
return;
|
||||
*p = 0xDEADBEEF; // expected-warning {{null}}
|
||||
}
|
||||
void RDar9267815::test() {
|
||||
int *p = 0;
|
||||
if (x == 42)
|
||||
return;
|
||||
if (x == 42)
|
||||
*p = 0xDEADBEEF; // no-warning
|
||||
}
|
||||
|
||||
void RDar9267815::test2() {
|
||||
int *p = 0;
|
||||
if (x == 42)
|
||||
return;
|
||||
invalidate();
|
||||
if (x == 42)
|
||||
*p = 0xDEADBEEF; // expected-warning {{null}}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue