1d99bd55aSTed Kremenek //=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This defines NoReturnFunctionChecker, which evaluates functions that do not
10d99bd55aSTed Kremenek // return to the caller.
11d99bd55aSTed Kremenek //
12d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13d99bd55aSTed Kremenek
1476a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
153a02247dSChandler Carruth #include "clang/AST/Attr.h"
16efef49cdSGeorge Karpenkov #include "clang/Analysis/SelectorExtras.h"
176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
18142dbbfcSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
194f7df9beSJordan Rose #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
20142dbbfcSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21d99bd55aSTed Kremenek #include "llvm/ADT/StringSwitch.h"
223cca223aSBenjamin Kramer #include <cstdarg>
23d99bd55aSTed Kremenek
24d99bd55aSTed Kremenek using namespace clang;
25d99bd55aSTed Kremenek using namespace ento;
26d99bd55aSTed Kremenek
27d99bd55aSTed Kremenek namespace {
28d99bd55aSTed Kremenek
29f77e7368SPavel Labath class NoReturnFunctionChecker : public Checker< check::PostCall,
305a3c9ff3SJordy Rose check::PostObjCMessage > {
310675c873SJordan Rose mutable Selector HandleFailureInFunctionSel;
320675c873SJordan Rose mutable Selector HandleFailureInMethodSel;
33d99bd55aSTed Kremenek public:
34f77e7368SPavel Labath void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
35547060b3SJordan Rose void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
36d99bd55aSTed Kremenek };
37d99bd55aSTed Kremenek
38ab9db510SAlexander Kornienko }
39d99bd55aSTed Kremenek
checkPostCall(const CallEvent & CE,CheckerContext & C) const40f77e7368SPavel Labath void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
41142dbbfcSArgyrios Kyrtzidis CheckerContext &C) const {
42f77e7368SPavel Labath bool BuildSinks = false;
43d99bd55aSTed Kremenek
44f77e7368SPavel Labath if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
459ead1243SAaron Ballman BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
46d99bd55aSTed Kremenek
47f77e7368SPavel Labath const Expr *Callee = CE.getOriginExpr();
48f77e7368SPavel Labath if (!BuildSinks && Callee)
49f77e7368SPavel Labath BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
50d99bd55aSTed Kremenek
51f77e7368SPavel Labath if (!BuildSinks && CE.isGlobalCFunction()) {
52f77e7368SPavel Labath if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
53d99bd55aSTed Kremenek // HACK: Some functions are not marked noreturn, and don't return.
54d99bd55aSTed Kremenek // Here are a few hardwired ones. If this takes too long, we can
55d99bd55aSTed Kremenek // potentially cache these results.
56d99bd55aSTed Kremenek BuildSinks
570e62c1ccSChris Lattner = llvm::StringSwitch<bool>(StringRef(II->getName()))
58d99bd55aSTed Kremenek .Case("exit", true)
59d99bd55aSTed Kremenek .Case("panic", true)
60d99bd55aSTed Kremenek .Case("error", true)
61d99bd55aSTed Kremenek .Case("Assert", true)
62d99bd55aSTed Kremenek // FIXME: This is just a wrapper around throwing an exception.
63d99bd55aSTed Kremenek // Eventually inter-procedural analysis should handle this easily.
64d99bd55aSTed Kremenek .Case("ziperr", true)
65d99bd55aSTed Kremenek .Case("assfail", true)
66d99bd55aSTed Kremenek .Case("db_error", true)
67d99bd55aSTed Kremenek .Case("__assert", true)
683369867aSDevin Coughlin .Case("__assert2", true)
69dba26928SJordan Rose // For the purpose of static analysis, we do not care that
70dba26928SJordan Rose // this MSVC function will return if the user decides to continue.
71dba26928SJordan Rose .Case("_wassert", true)
72d99bd55aSTed Kremenek .Case("__assert_rtn", true)
73d99bd55aSTed Kremenek .Case("__assert_fail", true)
74d99bd55aSTed Kremenek .Case("dtrace_assfail", true)
75d99bd55aSTed Kremenek .Case("yy_fatal_error", true)
76d99bd55aSTed Kremenek .Case("_XCAssertionFailureHandler", true)
77d99bd55aSTed Kremenek .Case("_DTAssertionFailureHandler", true)
78d99bd55aSTed Kremenek .Case("_TSAssertionFailureHandler", true)
79d99bd55aSTed Kremenek .Default(false);
80d99bd55aSTed Kremenek }
81d99bd55aSTed Kremenek }
82d99bd55aSTed Kremenek
83d99bd55aSTed Kremenek if (BuildSinks)
84e39bd407SDevin Coughlin C.generateSink(C.getState(), C.getPredecessor());
85d99bd55aSTed Kremenek }
86142dbbfcSArgyrios Kyrtzidis
checkPostObjCMessage(const ObjCMethodCall & Msg,CheckerContext & C) const87547060b3SJordan Rose void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
885a3c9ff3SJordy Rose CheckerContext &C) const {
8954cd3c68STed Kremenek // Check if the method is annotated with analyzer_noreturn.
905b4500b4STed Kremenek if (const ObjCMethodDecl *MD = Msg.getDecl()) {
915b4500b4STed Kremenek MD = MD->getCanonicalDecl();
9254cd3c68STed Kremenek if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
93e39bd407SDevin Coughlin C.generateSink(C.getState(), C.getPredecessor());
9454cd3c68STed Kremenek return;
9554cd3c68STed Kremenek }
965b4500b4STed Kremenek }
9754cd3c68STed Kremenek
985a3c9ff3SJordy Rose // HACK: This entire check is to handle two messages in the Cocoa frameworks:
995a3c9ff3SJordy Rose // -[NSAssertionHandler
1005a3c9ff3SJordy Rose // handleFailureInMethod:object:file:lineNumber:description:]
1015a3c9ff3SJordy Rose // -[NSAssertionHandler
1025a3c9ff3SJordy Rose // handleFailureInFunction:file:lineNumber:description:]
1035a3c9ff3SJordy Rose // Eventually these should be annotated with __attribute__((noreturn)).
1045a3c9ff3SJordy Rose // Because ObjC messages use dynamic dispatch, it is not generally safe to
1055a3c9ff3SJordy Rose // assume certain methods can't return. In cases where it is definitely valid,
1065a3c9ff3SJordy Rose // see if you can mark the methods noreturn or analyzer_noreturn instead of
1075a3c9ff3SJordy Rose // adding more explicit checks to this method.
1085a3c9ff3SJordy Rose
1095a3c9ff3SJordy Rose if (!Msg.isInstanceMessage())
1105a3c9ff3SJordy Rose return;
1115a3c9ff3SJordy Rose
1125a3c9ff3SJordy Rose const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
1135a3c9ff3SJordy Rose if (!Receiver)
1145a3c9ff3SJordy Rose return;
1155a3c9ff3SJordy Rose if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
1165a3c9ff3SJordy Rose return;
1175a3c9ff3SJordy Rose
1185a3c9ff3SJordy Rose Selector Sel = Msg.getSelector();
1195a3c9ff3SJordy Rose switch (Sel.getNumArgs()) {
1205a3c9ff3SJordy Rose default:
1215a3c9ff3SJordy Rose return;
1225a3c9ff3SJordy Rose case 4:
1230675c873SJordan Rose lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
1240675c873SJordan Rose "handleFailureInFunction", "file", "lineNumber",
1251d993270SSerge Guelton "description");
1260675c873SJordan Rose if (Sel != HandleFailureInFunctionSel)
1275a3c9ff3SJordy Rose return;
1285a3c9ff3SJordy Rose break;
1295a3c9ff3SJordy Rose case 5:
1300675c873SJordan Rose lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
1310675c873SJordan Rose "handleFailureInMethod", "object", "file",
1321d993270SSerge Guelton "lineNumber", "description");
1330675c873SJordan Rose if (Sel != HandleFailureInMethodSel)
1345a3c9ff3SJordy Rose return;
1355a3c9ff3SJordy Rose break;
1365a3c9ff3SJordy Rose }
1375a3c9ff3SJordy Rose
1385a3c9ff3SJordy Rose // If we got here, it's one of the messages we care about.
139e39bd407SDevin Coughlin C.generateSink(C.getState(), C.getPredecessor());
1405a3c9ff3SJordy Rose }
1415a3c9ff3SJordy Rose
registerNoReturnFunctionChecker(CheckerManager & mgr)142142dbbfcSArgyrios Kyrtzidis void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
143142dbbfcSArgyrios Kyrtzidis mgr.registerChecker<NoReturnFunctionChecker>();
144142dbbfcSArgyrios Kyrtzidis }
145058a7a45SKristof Umann
shouldRegisterNoReturnFunctionChecker(const CheckerManager & mgr)146*bda3dd0dSKirstóf Umann bool ento::shouldRegisterNoReturnFunctionChecker(const CheckerManager &mgr) {
147058a7a45SKristof Umann return true;
148058a7a45SKristof Umann }
149