summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/ProgramPoint.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h5
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h3
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h3
-rw-r--r--clang/lib/StaticAnalyzer/Core/CoreEngine.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp5
-rw-r--r--clang/test/Analysis/inlining/InlineObjCClassMethod.m4
-rw-r--r--clang/test/Analysis/unreachable-code-path.c12
8 files changed, 43 insertions, 15 deletions
diff --git a/clang/include/clang/Analysis/ProgramPoint.h b/clang/include/clang/Analysis/ProgramPoint.h
index 5045194ef86..be5adfb2942 100644
--- a/clang/include/clang/Analysis/ProgramPoint.h
+++ b/clang/include/clang/Analysis/ProgramPoint.h
@@ -622,8 +622,8 @@ private:
class CallExitBegin : public ProgramPoint {
public:
// CallExitBegin uses the callee's location context.
- CallExitBegin(const StackFrameContext *L)
- : ProgramPoint(nullptr, CallExitBeginKind, L, nullptr) {}
+ CallExitBegin(const StackFrameContext *L, const ReturnStmt *RS)
+ : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { }
private:
friend class ProgramPoint;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 0fa736d76c9..12ec5b6c64a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -109,7 +109,8 @@ private:
CoreEngine(const CoreEngine &) = delete;
void operator=(const CoreEngine &) = delete;
- ExplodedNode *generateCallExitBeginNode(ExplodedNode *N);
+ ExplodedNode *generateCallExitBeginNode(ExplodedNode *N,
+ const ReturnStmt *RS);
public:
/// Construct a CoreEngine object to analyze the provided CFG.
@@ -172,7 +173,7 @@ public:
/// \brief enqueue the nodes corresponding to the end of function onto the
/// end of path / work list.
- void enqueueEndOfFunction(ExplodedNodeSet &Set);
+ void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS);
/// \brief Enqueue a single node created as a result of statement processing.
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 50d85057041..e5ffb431ba3 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -262,7 +262,8 @@ public:
/// Called by CoreEngine. Used to notify checkers that processing a
/// function has ended. Called for both inlined and and top-level functions.
void processEndOfFunction(NodeBuilderContext& BC,
- ExplodedNode *Pred) override;
+ ExplodedNode *Pred,
+ const ReturnStmt *RS=nullptr) override;
/// Remove dead bindings/symbols before exiting a function.
void removeDeadOnEndOfFunction(NodeBuilderContext& BC,
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 1a731cf865e..1f599ed255b 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -109,7 +109,8 @@ public:
/// Called by CoreEngine. Used to notify checkers that processing a
/// function has ended. Called for both inlined and and top-level functions.
virtual void processEndOfFunction(NodeBuilderContext& BC,
- ExplodedNode *Pred) = 0;
+ ExplodedNode *Pred,
+ const ReturnStmt *RS = nullptr) = 0;
// Generate the entry node of the callee.
virtual void processCallEnter(NodeBuilderContext& BC, CallEnter CE,
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index a0f994e4f40..ea809b7067f 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -309,8 +309,19 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
assert (L.getLocationContext()->getCFG()->getExit().size() == 0
&& "EXIT block cannot contain Stmts.");
+ // Get return statement..
+ const ReturnStmt *RS = nullptr;
+ if (!L.getSrc()->empty()) {
+ if (Optional<CFGStmt> LastStmt = L.getSrc()->back().getAs<CFGStmt>()) {
+ if (RS = dyn_cast<ReturnStmt>(LastStmt->getStmt())) {
+ if (!RS->getRetValue())
+ RS = nullptr;
+ }
+ }
+ }
+
// Process the final state transition.
- SubEng.processEndOfFunction(BuilderCtx, Pred);
+ SubEng.processEndOfFunction(BuilderCtx, Pred, RS);
// This path is done. Don't enqueue any more nodes.
return;
@@ -589,13 +600,14 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
WList->enqueue(Succ, Block, Idx+1);
}
-ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) {
+ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N,
+ const ReturnStmt *RS) {
// Create a CallExitBegin node and enqueue it.
const StackFrameContext *LocCtx
= cast<StackFrameContext>(N->getLocationContext());
// Use the callee location context.
- CallExitBegin Loc(LocCtx);
+ CallExitBegin Loc(LocCtx, RS);
bool isNew;
ExplodedNode *Node = G.getNode(Loc, N->getState(), false, &isNew);
@@ -619,12 +631,12 @@ void CoreEngine::enqueue(ExplodedNodeSet &Set,
}
}
-void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set) {
+void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS) {
for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) {
ExplodedNode *N = *I;
// If we are in an inlined call, generate CallExitBegin node.
if (N->getLocationContext()->getParent()) {
- N = generateCallExitBeginNode(N);
+ N = generateCallExitBeginNode(N, RS);
if (N)
WList->enqueue(N);
} else {
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 179beff4c2f..f24e0714afe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1766,7 +1766,8 @@ void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC,
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
- ExplodedNode *Pred) {
+ ExplodedNode *Pred,
+ const ReturnStmt *RS) {
// FIXME: Assert that stackFrameDoesNotContainInitializedTemporaries(*Pred)).
// We currently cannot enable this assert, as lifetime extended temporaries
// are not modelled correctly.
@@ -1788,7 +1789,7 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this);
}
- Engine.enqueueEndOfFunction(Dst);
+ Engine.enqueueEndOfFunction(Dst, RS);
}
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
diff --git a/clang/test/Analysis/inlining/InlineObjCClassMethod.m b/clang/test/Analysis/inlining/InlineObjCClassMethod.m
index 6efcb894fec..c9cc90ba27c 100644
--- a/clang/test/Analysis/inlining/InlineObjCClassMethod.m
+++ b/clang/test/Analysis/inlining/InlineObjCClassMethod.m
@@ -174,12 +174,12 @@ int foo4() {
@implementation MyClassSelf
+ (int)testClassMethodByKnownVarDecl {
int y = [MyParentSelf testSelf];
- return 5/y; // Should warn here.
+ return 5/y; // expected-warning{{Division by zero}}
}
@end
int foo2() {
int y = [MyParentSelf testSelf];
- return 5/y; // Should warn here.
+ return 5/y; // expected-warning{{Division by zero}}
}
// TODO: We do not inline 'getNum' in the following case, where the value of
diff --git a/clang/test/Analysis/unreachable-code-path.c b/clang/test/Analysis/unreachable-code-path.c
index f0db575ba49..975c9887e45 100644
--- a/clang/test/Analysis/unreachable-code-path.c
+++ b/clang/test/Analysis/unreachable-code-path.c
@@ -194,3 +194,15 @@ void test12(int x) {
break;
}
}
+
+// Don't merge return nodes in ExplodedGraph unless they are same.
+extern int table[];
+static int inlineFunction(const int i) {
+ if (table[i] != 0)
+ return 1;
+ return 0;
+}
+void test13(int i) {
+ int x = inlineFunction(i);
+ x && x < 10; // no-warning
+}
OpenPOWER on IntegriCloud