diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-05-25 23:57:29 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-05-25 23:57:29 +0000 |
commit | e5cfd52a3a5d4bb46f77323fa8fa0b973fcde7bc (patch) | |
tree | 02a63c700337cf10575e51ed7f98aa89b651e6bc | |
parent | 82713174914bdb927a254c5ee188e35fd79c4948 (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.h | 8 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CFRefCount.cpp | 12 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 21 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ObjCMessage.cpp | 7 | ||||
-rw-r--r-- | test/Analysis/misc-ps.c | 38 |
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; +} + |