clang  6.0.0svn
NoReturnFunctionChecker.cpp
Go to the documentation of this file.
1 //=== NoReturnFunctionChecker.cpp -------------------------------*- 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 defines NoReturnFunctionChecker, which evaluates functions that do not
11 // return to the caller.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "SelectorExtras.h"
17 #include "clang/AST/Attr.h"
22 #include "llvm/ADT/StringSwitch.h"
23 #include <cstdarg>
24 
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 
30 class NoReturnFunctionChecker : public Checker< check::PostCall,
31  check::PostObjCMessage > {
32  mutable Selector HandleFailureInFunctionSel;
33  mutable Selector HandleFailureInMethodSel;
34 public:
35  void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
36  void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
37 };
38 
39 }
40 
41 void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
42  CheckerContext &C) const {
43  bool BuildSinks = false;
44 
45  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
46  BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
47 
48  const Expr *Callee = CE.getOriginExpr();
49  if (!BuildSinks && Callee)
50  BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
51 
52  if (!BuildSinks && CE.isGlobalCFunction()) {
53  if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
54  // HACK: Some functions are not marked noreturn, and don't return.
55  // Here are a few hardwired ones. If this takes too long, we can
56  // potentially cache these results.
57  BuildSinks
58  = llvm::StringSwitch<bool>(StringRef(II->getName()))
59  .Case("exit", true)
60  .Case("panic", true)
61  .Case("error", true)
62  .Case("Assert", true)
63  // FIXME: This is just a wrapper around throwing an exception.
64  // Eventually inter-procedural analysis should handle this easily.
65  .Case("ziperr", true)
66  .Case("assfail", true)
67  .Case("db_error", true)
68  .Case("__assert", true)
69  .Case("__assert2", true)
70  // For the purpose of static analysis, we do not care that
71  // this MSVC function will return if the user decides to continue.
72  .Case("_wassert", true)
73  .Case("__assert_rtn", true)
74  .Case("__assert_fail", true)
75  .Case("dtrace_assfail", true)
76  .Case("yy_fatal_error", true)
77  .Case("_XCAssertionFailureHandler", true)
78  .Case("_DTAssertionFailureHandler", true)
79  .Case("_TSAssertionFailureHandler", true)
80  .Default(false);
81  }
82  }
83 
84  if (BuildSinks)
86 }
87 
88 void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
89  CheckerContext &C) const {
90  // Check if the method is annotated with analyzer_noreturn.
91  if (const ObjCMethodDecl *MD = Msg.getDecl()) {
92  MD = MD->getCanonicalDecl();
93  if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
95  return;
96  }
97  }
98 
99  // HACK: This entire check is to handle two messages in the Cocoa frameworks:
100  // -[NSAssertionHandler
101  // handleFailureInMethod:object:file:lineNumber:description:]
102  // -[NSAssertionHandler
103  // handleFailureInFunction:file:lineNumber:description:]
104  // Eventually these should be annotated with __attribute__((noreturn)).
105  // Because ObjC messages use dynamic dispatch, it is not generally safe to
106  // assume certain methods can't return. In cases where it is definitely valid,
107  // see if you can mark the methods noreturn or analyzer_noreturn instead of
108  // adding more explicit checks to this method.
109 
110  if (!Msg.isInstanceMessage())
111  return;
112 
113  const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
114  if (!Receiver)
115  return;
116  if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
117  return;
118 
119  Selector Sel = Msg.getSelector();
120  switch (Sel.getNumArgs()) {
121  default:
122  return;
123  case 4:
124  lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
125  "handleFailureInFunction", "file", "lineNumber",
126  "description");
127  if (Sel != HandleFailureInFunctionSel)
128  return;
129  break;
130  case 5:
131  lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
132  "handleFailureInMethod", "object", "file",
133  "lineNumber", "description");
134  if (Sel != HandleFailureInMethodSel)
135  return;
136  break;
137  }
138 
139  // If we got here, it's one of the messages we care about.
141 }
142 
143 void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
144  mgr.registerChecker<NoReturnFunctionChecker>();
145 }
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
Smart pointer class that efficiently represents Objective-C method names.
static void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx, IdentifierInfos *... IIs)
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
Definition: CallEvent.h:225
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:265
One of these records is kept for each identifier that is lexed.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Definition: CallEvent.h:928
Represents any expression that calls an Objective-C method.
Definition: CallEvent.h:870
Represents an ObjC class declaration.
Definition: DeclObjC.h:1191
Expr - This represents one expression.
Definition: Expr.h:106
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Definition: CallEvent.h:335
QualType getType() const
Definition: Expr.h:128
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
Definition: CallEvent.h:205
unsigned getNumArgs() const
CHECKER * registerChecker()
Used to register checkers.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
const ObjCMethodDecl * getDecl() const override
Definition: CallEvent.h:896
Selector getSelector() const
Definition: CallEvent.h:912
Dataflow Directional Tag Classes.
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
Definition: Type.h:5845
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:140
bool isInstanceMessage() const
Definition: CallEvent.h:906
const ProgramStateRef & getState() const
bool isGlobalCFunction(StringRef SpecificName=StringRef()) const
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
Definition: CallEvent.cpp:121