From 8ef59e5c03c937056cd0282fe9747be2978a973e Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Mon, 11 Apr 2011 22:22:05 +0000 Subject: [PATCH] C++ static analysis: also invalidate fields of objects that are the callees in C++ method calls. llvm-svn: 129308 --- .../Core/PathSensitive/ObjCMessage.h | 24 ++++++++++---- clang/lib/StaticAnalyzer/Core/CFRefCount.cpp | 8 +++++ clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp | 9 ++++- clang/test/Analysis/misc-ps-region-store.cpp | 33 +++++++++++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h index dda855fb826e..6d8fc89a4839 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -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(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); } }; diff --git a/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp b/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp index 5131c7392574..df82c5820497 100644 --- a/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -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(); diff --git a/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp index c44d36ae49f5..c005819c9c96 100644 --- a/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -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(CallE)->getImplicitObjectArgument(); + return State->getSVal(callee); +} diff --git a/clang/test/Analysis/misc-ps-region-store.cpp b/clang/test/Analysis/misc-ps-region-store.cpp index 2b79bdbd8291..94bfc278b545 100644 --- a/clang/test/Analysis/misc-ps-region-store.cpp +++ b/clang/test/Analysis/misc-ps-region-store.cpp @@ -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}} +} +