]> granicus.if.org Git - clang/commitdiff
static analyzer: when conservatively evaluating functions, don't invalidate the value...
authorTed Kremenek <kremenek@apple.com>
Wed, 25 May 2011 23:57:29 +0000 (23:57 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 25 May 2011 23:57:29 +0000 (23:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132100 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
lib/StaticAnalyzer/Core/CFRefCount.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ObjCMessage.cpp
test/Analysis/misc-ps.c [new file with mode: 0644]

index 99df4f0fdbe642cf86409c07c093eb51ebaca442..d24036c0ec28dd338828424f47d03f316c49ff6f 100644 (file)
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/ExprObjC.h"
@@ -460,6 +461,13 @@ private:
                     const void *tag, bool isLoad);
 
   bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+  
+  
+public:
+  /// Returns true if calling the specific function or method would possibly
+  /// cause global variables to be invalidated.
+  bool doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const;
+  
 };
 
 } // end ento namespace
index 6d8fc89a4839edceefffe34c9ad7b7bcbe439421..734024c2cba4c9ed837d1b188e09efbceec85d82 100644 (file)
@@ -187,6 +187,7 @@ public:
     return CallE && isa<CXXMemberCallExpr>(CallE);
   }
   
+  SVal getFunctionCallee() const;
   SVal getCXXCallee() const;
 
   unsigned getNumArgs() const {
index 59fea1031ffa824a89723042564fbf24a0bd7c4d..013eeec0e4bb064ef4ab6be66771ab43bb44c824 100644 (file)
@@ -2664,11 +2664,13 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
   // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
   //  global variables.
   // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
-  state = state->invalidateRegions(RegionsToInvalidate.data(),
-                                   RegionsToInvalidate.data() +
-                                   RegionsToInvalidate.size(),
-                                   Ex, Count, &IS,
-                                   /* invalidateGlobals = */ true);
+  state =
+    state->invalidateRegions(RegionsToInvalidate.data(),
+                             RegionsToInvalidate.data() +
+                             RegionsToInvalidate.size(),
+                             Ex, Count, &IS,
+                             /* invalidateGlobals = */
+                             Eng.doesInvalidateGlobals(callOrMsg));
 
   // Evaluate the effect on the message receiver.
   if (!ErrorRange.isValid() && Receiver) {
index 4b7d999bd4a9e533a3944f4aec84743c335d6656..6fd66c1f310c5f655bb9e563bf1bfb446af86960 100644 (file)
@@ -156,6 +156,27 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
   return state;
 }
 
+bool
+ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
+{
+  if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
+    SVal calleeV = callOrMessage.getFunctionCallee();
+    if (const FunctionTextRegion *codeR =
+          llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
+      
+      const FunctionDecl *fd = codeR->getDecl();
+      if (const IdentifierInfo *ii = fd->getIdentifier()) {
+        llvm::StringRef fname = ii->getName();
+        if (fname == "strlen")
+          return false;
+      }
+    }
+  }
+  
+  // The conservative answer: invalidates globals.
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Top-level transfer function logic (Dispatcher).
 //===----------------------------------------------------------------------===//
index c005819c9c9682619f750ee0ed3f5a3f2dd3bed4..c000600474980c70a433cc87a77dd870cd381fe1 100644 (file)
@@ -141,6 +141,13 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
   return UnknownVal();
 }
 
+SVal CallOrObjCMessage::getFunctionCallee() const {
+  assert(isFunctionCall());
+  assert(!isCXXCall());
+  const Expr *callee = CallE->getCallee()->IgnoreParenCasts();
+  return State->getSVal(callee);
+}
+
 SVal CallOrObjCMessage::getCXXCallee() const {
   assert(isCXXCall());
   const Expr *callee =
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
new file mode 100644 (file)
index 0000000..2d4fdd4
--- /dev/null
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s
+
+unsigned long strlen(const char *);
+
+int size_rdar9373039 = 1;
+int rdar9373039() {
+  int x;
+  int j = 0;
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    x = 1;
+    
+  // strlen doesn't invalidate the value of 'size_rdar9373039'.
+  int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4));
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    j += x; // no-warning
+
+  return j;
+}
+
+int foo_rdar9373039(const char *);
+
+int rdar93730392() {
+  int x;
+  int j = 0;
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    x = 1;
+    
+  int extra = (2 + foo_rdar9373039 ("Clang") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("Clang")) % 4)) % 4)) + (2 + foo_rdar9373039 ("1.0") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("1.0")) % 4)) % 4)); // expected-warning {{never read}}
+
+  for (int i = 0 ; i < size_rdar9373039 ; ++i)
+    j += x; // expected-warning {{garbage}}
+
+  return j;
+}
+