aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-05-25 23:57:29 +0000
committerTed Kremenek <kremenek@apple.com>2011-05-25 23:57:29 +0000
commite5cfd52a3a5d4bb46f77323fa8fa0b973fcde7bc (patch)
tree02a63c700337cf10575e51ed7f98aa89b651e6bc
parent82713174914bdb927a254c5ee188e35fd79c4948 (diff)
static analyzer: when conservatively evaluating functions, don't invalidate the values of globals when the called function is strlen.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132100 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h1
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp21
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp7
-rw-r--r--test/Analysis/misc-ps.c38
6 files changed, 82 insertions, 5 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 99df4f0fdb..d24036c0ec 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -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
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 6d8fc89a48..734024c2cb 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -187,6 +187,7 @@ public:
return CallE && isa<CXXMemberCallExpr>(CallE);
}
+ SVal getFunctionCallee() const;
SVal getCXXCallee() const;
unsigned getNumArgs() const {
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 59fea1031f..013eeec0e4 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -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) {
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 4b7d999bd4..6fd66c1f31 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -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).
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index c005819c9c..c000600474 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -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
index 0000000000..2d4fdd4637
--- /dev/null
+++ b/test/Analysis/misc-ps.c
@@ -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;
+}
+