Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 4ef1920

Browse files
committed
Refactor logic in ExprEngine for detecting 'noreturn' methods
in NSException to a helper object in libAnalysis that can also be used by Sema. Not sure if the predicate name 'isImplicitNoReturn' is the best one, but we can massage that later. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163759 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 3ef95a5 commit 4ef1920

File tree

6 files changed

+129
-66
lines changed

6 files changed

+129
-66
lines changed

Diff for: include/clang/Analysis/DomainSpecific/ObjCNoReturn.h

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- C++ -*---//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements special handling of recognizing ObjC API hooks that
11+
// do not return but aren't marked as such in API headers.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
16+
#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
17+
18+
#include "clang/Basic/IdentifierTable.h"
19+
20+
namespace clang {
21+
22+
class ASTContext;
23+
class ObjCMessageExpr;
24+
25+
class ObjCNoReturn {
26+
/// Cached "raise" selector.
27+
Selector RaiseSel;
28+
29+
/// Cached identifier for "NSException".
30+
IdentifierInfo *NSExceptionII;
31+
32+
enum { NUM_RAISE_SELECTORS = 2 };
33+
34+
/// Cached set of selectors in NSException that are 'noreturn'.
35+
Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS];
36+
37+
public:
38+
ObjCNoReturn(ASTContext &C);
39+
40+
/// Return true if the given message expression is known to never
41+
/// return.
42+
bool isImplicitNoReturn(const ObjCMessageExpr *ME);
43+
};
44+
}
45+
46+
#endif

Diff for: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

+5-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#ifndef LLVM_CLANG_GR_EXPRENGINE
1717
#define LLVM_CLANG_GR_EXPRENGINE
1818

19+
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
1920
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
2021
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
2122
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
@@ -74,13 +75,10 @@ class ExprEngine : public SubEngine {
7475
const Stmt *currStmt;
7576
unsigned int currStmtIdx;
7677
const NodeBuilderContext *currBldrCtx;
77-
78-
/// Obj-C Class Identifiers.
79-
IdentifierInfo* NSExceptionII;
80-
81-
/// Obj-C Selectors.
82-
Selector* NSExceptionInstanceRaiseSelectors;
83-
Selector RaiseSel;
78+
79+
/// Helper object to determine if an Objective-C message expression
80+
/// implicitly never returns.
81+
ObjCNoReturn ObjCNoRet;
8482

8583
/// Whether or not GC is enabled in this analysis.
8684
bool ObjCGCEnabled;

Diff for: lib/Analysis/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
add_clang_library(clangAnalysis
22
AnalysisDeclContext.cpp
3-
CallGraph.cpp
43
CFG.cpp
54
CFGReachabilityAnalysis.cpp
65
CFGStmtMap.cpp
6+
CallGraph.cpp
77
CocoaConventions.cpp
88
Dominators.cpp
99
FormatString.cpp
1010
LiveVariables.cpp
11+
ObjCNoReturn.cpp
1112
PostOrderCFGView.cpp
1213
PrintfFormatString.cpp
1314
ProgramPoint.cpp

Diff for: lib/Analysis/ObjCNoReturn.cpp

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- C++ -*---
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements special handling of recognizing ObjC API hooks that
11+
// do not return but aren't marked as such in API headers.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "clang/AST/ASTContext.h"
16+
#include "clang/AST/ExprObjC.h"
17+
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
18+
19+
using namespace clang;
20+
21+
static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
22+
if (!Class)
23+
return false;
24+
if (Class->getIdentifier() == II)
25+
return true;
26+
return isSubclass(Class->getSuperClass(), II);
27+
}
28+
29+
ObjCNoReturn::ObjCNoReturn(ASTContext &C)
30+
: RaiseSel(GetNullarySelector("raise", C)),
31+
NSExceptionII(&C.Idents.get("NSException"))
32+
{
33+
// Generate selectors.
34+
SmallVector<IdentifierInfo*, 3> II;
35+
36+
// raise:format:
37+
II.push_back(&C.Idents.get("raise"));
38+
II.push_back(&C.Idents.get("format"));
39+
NSExceptionInstanceRaiseSelectors[0] =
40+
C.Selectors.getSelector(II.size(), &II[0]);
41+
42+
// raise:format:arguments:
43+
II.push_back(&C.Idents.get("arguments"));
44+
NSExceptionInstanceRaiseSelectors[1] =
45+
C.Selectors.getSelector(II.size(), &II[0]);
46+
}
47+
48+
49+
bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
50+
Selector S = ME->getSelector();
51+
52+
if (ME->isInstanceMessage()) {
53+
// Check for the "raise" message.
54+
return S == RaiseSel;
55+
}
56+
57+
if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
58+
if (isSubclass(ID, NSExceptionII)) {
59+
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
60+
if (S == NSExceptionInstanceRaiseSelectors[i])
61+
return true;
62+
}
63+
}
64+
}
65+
66+
return false;
67+
}

Diff for: lib/StaticAnalyzer/Core/ExprEngine.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
6868
svalBuilder(StateMgr.getSValBuilder()),
6969
EntryNode(NULL),
7070
currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
71-
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
72-
RaiseSel(GetNullarySelector("raise", getContext())),
71+
ObjCNoRet(mgr.getASTContext()),
7372
ObjCGCEnabled(gcEnabled), BR(mgr, *this),
7473
VisitedCallees(VisitedCalleesIn)
7574
{
@@ -81,7 +80,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
8180

8281
ExprEngine::~ExprEngine() {
8382
BR.FlushReports();
84-
delete [] NSExceptionInstanceRaiseSelectors;
8583
}
8684

8785
//===----------------------------------------------------------------------===//

Diff for: lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

+8-55
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
132132
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
133133
}
134134

135-
static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
136-
if (!Class)
137-
return false;
138-
if (Class->getIdentifier() == II)
139-
return true;
140-
return isSubclass(Class->getSuperClass(), II);
141-
}
142-
143135
void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
144136
ExplodedNode *Pred,
145137
ExplodedNodeSet &Dst) {
@@ -184,7 +176,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
184176

185177
// Check if the "raise" message was sent.
186178
assert(notNilState);
187-
if (Msg->getSelector() == RaiseSel) {
179+
if (ObjCNoRet.isImplicitNoReturn(ME)) {
188180
// If we raise an exception, for now treat it as a sink.
189181
// Eventually we will want to handle exceptions properly.
190182
Bldr.generateSink(currStmt, Pred, State);
@@ -198,52 +190,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
198190
}
199191
}
200192
} else {
201-
// Check for special class methods.
202-
if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
203-
if (!NSExceptionII) {
204-
ASTContext &Ctx = getContext();
205-
NSExceptionII = &Ctx.Idents.get("NSException");
206-
}
207-
208-
if (isSubclass(Iface, NSExceptionII)) {
209-
enum { NUM_RAISE_SELECTORS = 2 };
210-
211-
// Lazily create a cache of the selectors.
212-
if (!NSExceptionInstanceRaiseSelectors) {
213-
ASTContext &Ctx = getContext();
214-
NSExceptionInstanceRaiseSelectors =
215-
new Selector[NUM_RAISE_SELECTORS];
216-
SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
217-
unsigned idx = 0;
218-
219-
// raise:format:
220-
II.push_back(&Ctx.Idents.get("raise"));
221-
II.push_back(&Ctx.Idents.get("format"));
222-
NSExceptionInstanceRaiseSelectors[idx++] =
223-
Ctx.Selectors.getSelector(II.size(), &II[0]);
224-
225-
// raise:format:arguments:
226-
II.push_back(&Ctx.Idents.get("arguments"));
227-
NSExceptionInstanceRaiseSelectors[idx++] =
228-
Ctx.Selectors.getSelector(II.size(), &II[0]);
229-
}
230-
231-
Selector S = Msg->getSelector();
232-
bool RaisesException = false;
233-
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
234-
if (S == NSExceptionInstanceRaiseSelectors[i]) {
235-
RaisesException = true;
236-
break;
237-
}
238-
}
239-
if (RaisesException) {
240-
// If we raise an exception, for now treat it as a sink.
241-
// Eventually we will want to handle exceptions properly.
242-
Bldr.generateSink(currStmt, Pred, Pred->getState());
243-
continue;
244-
}
245-
246-
}
193+
// Check for special class methods that are known to not return
194+
// and that we should treat as a sink.
195+
if (ObjCNoRet.isImplicitNoReturn(ME)) {
196+
// If we raise an exception, for now treat it as a sink.
197+
// Eventually we will want to handle exceptions properly.
198+
Bldr.generateSink(currStmt, Pred, Pred->getState());
199+
continue;
247200
}
248201
}
249202

0 commit comments

Comments
 (0)