summaryrefslogtreecommitdiffstats
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
commit4c5d2888f46788f1970994e7607de33ca8c03a0e (patch)
treeb0a2fa1c0c80f5bfeb8772a7bbf838cd60ac7ad3
parentc70355195cfffc79108eaa4a190095a3050b144a (diff)
downloadbcm5719-llvm-4c5d2888f46788f1970994e7607de33ca8c03a0e.tar.gz
bcm5719-llvm-4c5d2888f46788f1970994e7607de33ca8c03a0e.zip
static analyzer: when conservatively evaluating functions, don't invalidate the values of globals when the called function is strlen.
llvm-svn: 132100
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h8
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h1
-rw-r--r--clang/lib/StaticAnalyzer/Core/CFRefCount.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp7
-rw-r--r--clang/test/Analysis/misc-ps.c38
6 files changed, 82 insertions, 5 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 99df4f0fdbe..d24036c0ec2 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/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/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 6d8fc89a483..734024c2cba 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp b/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 59fea1031ff..013eeec0e4b 100644
--- a/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 4b7d999bd4a..6fd66c1f310 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index c005819c9c9..c0006004749 100644
--- a/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/clang/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/clang/test/Analysis/misc-ps.c b/clang/test/Analysis/misc-ps.c
new file mode 100644
index 00000000000..2d4fdd4637d
--- /dev/null
+++ b/clang/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;
+}
+
OpenPOWER on IntegriCloud