]> granicus.if.org Git - clang/commitdiff
C++ static analysis: also invalidate fields of objects that are the callees in C...
authorTed Kremenek <kremenek@apple.com>
Mon, 11 Apr 2011 22:22:05 +0000 (22:22 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 11 Apr 2011 22:22:05 +0000 (22:22 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129308 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
lib/StaticAnalyzer/Core/CFRefCount.cpp
lib/StaticAnalyzer/Core/ObjCMessage.cpp
test/Analysis/misc-ps-region-store.cpp

index dda855fb826e0dd178563801e80efbbd798751b1..6d8fc89a4839edceefffe34c9ad7b7bcbe439421 100644 (file)
@@ -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);
   }
 };
index 5131c73925749e10c2567ee6b64339e9162b9144..df82c582049717574b80d1c2d8019bf6659ff352 100644 (file)
@@ -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();
index c44d36ae49f5a5153997e2e9b8e49daf45582109..c005819c9c9682619f750ee0ed3f5a3f2dd3bed4 100644 (file)
@@ -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);  
+}
index 2b79bdbd829111117c904f543ca58fba44fb3712..94bfc278b545a90cd93669f83ce089413d89b521 100644 (file)
@@ -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}}
+}
+