clang  3.7.0
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  // For the purpose of static analysis, we do not care that
70  // this MSVC function will return if the user decides to continue.
71  .Case("_wassert", true)
72  .Case("__assert_rtn", true)
73  .Case("__assert_fail", true)
74  .Case("dtrace_assfail", true)
75  .Case("yy_fatal_error", true)
76  .Case("_XCAssertionFailureHandler", true)
77  .Case("_DTAssertionFailureHandler", true)
78  .Case("_TSAssertionFailureHandler", true)
79  .Default(false);
80  }
81  }
82 
83  if (BuildSinks)
84  C.generateSink();
85 }
86 
87 void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
88  CheckerContext &C) const {
89  // Check if the method is annotated with analyzer_noreturn.
90  if (const ObjCMethodDecl *MD = Msg.getDecl()) {
91  MD = MD->getCanonicalDecl();
92  if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
93  C.generateSink();
94  return;
95  }
96  }
97 
98  // HACK: This entire check is to handle two messages in the Cocoa frameworks:
99  // -[NSAssertionHandler
100  // handleFailureInMethod:object:file:lineNumber:description:]
101  // -[NSAssertionHandler
102  // handleFailureInFunction:file:lineNumber:description:]
103  // Eventually these should be annotated with __attribute__((noreturn)).
104  // Because ObjC messages use dynamic dispatch, it is not generally safe to
105  // assume certain methods can't return. In cases where it is definitely valid,
106  // see if you can mark the methods noreturn or analyzer_noreturn instead of
107  // adding more explicit checks to this method.
108 
109  if (!Msg.isInstanceMessage())
110  return;
111 
112  const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
113  if (!Receiver)
114  return;
115  if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
116  return;
117 
118  Selector Sel = Msg.getSelector();
119  switch (Sel.getNumArgs()) {
120  default:
121  return;
122  case 4:
123  lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
124  "handleFailureInFunction", "file", "lineNumber",
125  "description", nullptr);
126  if (Sel != HandleFailureInFunctionSel)
127  return;
128  break;
129  case 5:
130  lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
131  "handleFailureInMethod", "object", "file",
132  "lineNumber", "description", nullptr);
133  if (Sel != HandleFailureInMethodSel)
134  return;
135  break;
136  }
137 
138  // If we got here, it's one of the messages we care about.
139  C.generateSink();
140 }
141 
142 void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
143  mgr.registerChecker<NoReturnFunctionChecker>();
144 }
Smart pointer class that efficiently represents Objective-C method names.
bool isInstanceMessage() const
Definition: CallEvent.h:826
IdentifierInfo * getIdentifier() const
Definition: Decl.h:163
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Definition: CallEvent.h:848
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call. May be null.
Definition: CallEvent.h:197
Represents any expression that calls an Objective-C method.
Definition: CallEvent.h:791
Represents an ObjC class declaration.
Definition: DeclObjC.h:851
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
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:103
unsigned getNumArgs() const
static LLVM_END_WITH_NULL void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx, const char *First,...)
CHECKER * registerChecker()
Used to register checkers.
Selector getSelector() const
Definition: CallEvent.h:832
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Definition: CallEvent.h:293
const ObjCMethodDecl * getDecl() const override
Definition: CallEvent.h:816
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called. May be null.
Definition: CallEvent.h:177
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
QualType getType() const
Definition: Expr.h:125
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
Definition: Type.h:5140
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:113