clang  14.0.0git
NoReturnFunctionChecker.cpp
Go to the documentation of this file.
1 //=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This defines NoReturnFunctionChecker, which evaluates functions that do not
10 // return to the caller.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "clang/AST/Attr.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include <cstdarg>
23 
24 using namespace clang;
25 using namespace ento;
26 
27 namespace {
28 
29 class NoReturnFunctionChecker : public Checker< check::PostCall,
30  check::PostObjCMessage > {
31  mutable Selector HandleFailureInFunctionSel;
32  mutable Selector HandleFailureInMethodSel;
33 public:
34  void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
35  void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
36 };
37 
38 }
39 
40 void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
41  CheckerContext &C) const {
42  bool BuildSinks = false;
43 
44  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
45  BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
46 
47  const Expr *Callee = CE.getOriginExpr();
48  if (!BuildSinks && Callee)
49  BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
50 
51  if (!BuildSinks && CE.isGlobalCFunction()) {
52  if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
53  // HACK: Some functions are not marked noreturn, and don't return.
54  // Here are a few hardwired ones. If this takes too long, we can
55  // potentially cache these results.
56  BuildSinks
57  = llvm::StringSwitch<bool>(StringRef(II->getName()))
58  .Case("exit", true)
59  .Case("panic", true)
60  .Case("error", true)
61  .Case("Assert", true)
62  // FIXME: This is just a wrapper around throwing an exception.
63  // Eventually inter-procedural analysis should handle this easily.
64  .Case("ziperr", true)
65  .Case("assfail", true)
66  .Case("db_error", true)
67  .Case("__assert", true)
68  .Case("__assert2", 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(C.getState(), C.getPredecessor());
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(C.getState(), C.getPredecessor());
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");
126  if (Sel != HandleFailureInFunctionSel)
127  return;
128  break;
129  case 5:
130  lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
131  "handleFailureInMethod", "object", "file",
132  "lineNumber", "description");
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(C.getState(), C.getPredecessor());
140 }
141 
142 void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
143  mgr.registerChecker<NoReturnFunctionChecker>();
144 }
145 
146 bool ento::shouldRegisterNoReturnFunctionChecker(const CheckerManager &mgr) {
147  return true;
148 }
clang::lazyInitKeywordSelector
static void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx, IdentifierInfos *... IIs)
Definition: SelectorExtras.h:27
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1151
Attr.h
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::getFunctionExtInfo
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
Definition: Type.h:6573
CallEvent.h
clang::IdentifierInfo::isStr
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Definition: IdentifierTable.h:176
BuiltinCheckerRegistration.h
clang::syntax::NodeRole::Callee
@ Callee
clang::FunctionType::ExtInfo::getNoReturn
bool getNoReturn() const
Definition: Type.h:3705
CheckerManager.h
clang::Selector::getNumArgs
unsigned getNumArgs() const
Definition: IdentifierTable.cpp:480
clang::NamedDecl::getIdentifier
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
SelectorExtras.h
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
CheckerContext.h
Checker.h
clang::ObjCMethodDecl
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
clang
Definition: CalledOnceCheck.h:17
clang::Selector
Smart pointer class that efficiently represents Objective-C method names.
Definition: IdentifierTable.h:748
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856