NoReturnFunctionChecker.cpp revision 18c66fdc3c4008d335885695fe36fb5353c5f672
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 "clang/StaticAnalyzer/Core/Checker.h"
17#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19#include "llvm/ADT/StringSwitch.h"
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25
26class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr> > {
27public:
28  void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
29};
30
31}
32
33void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
34                                            CheckerContext &C) const {
35  const ProgramState *state = C.getState();
36  const Expr *Callee = CE->getCallee();
37
38  bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
39
40  if (!BuildSinks) {
41    SVal L = state->getSVal(Callee);
42    const FunctionDecl *FD = L.getAsFunctionDecl();
43    if (!FD)
44      return;
45
46    if (FD->getAttr<AnalyzerNoReturnAttr>())
47      BuildSinks = true;
48    else if (const IdentifierInfo *II = FD->getIdentifier()) {
49      // HACK: Some functions are not marked noreturn, and don't return.
50      //  Here are a few hardwired ones.  If this takes too long, we can
51      //  potentially cache these results.
52      BuildSinks
53        = llvm::StringSwitch<bool>(StringRef(II->getName()))
54            .Case("exit", true)
55            .Case("panic", true)
56            .Case("error", true)
57            .Case("Assert", true)
58            // FIXME: This is just a wrapper around throwing an exception.
59            //  Eventually inter-procedural analysis should handle this easily.
60            .Case("ziperr", true)
61            .Case("assfail", true)
62            .Case("db_error", true)
63            .Case("__assert", true)
64            .Case("__assert_rtn", true)
65            .Case("__assert_fail", true)
66            .Case("dtrace_assfail", true)
67            .Case("yy_fatal_error", true)
68            .Case("_XCAssertionFailureHandler", true)
69            .Case("_DTAssertionFailureHandler", true)
70            .Case("_TSAssertionFailureHandler", true)
71            .Default(false);
72    }
73  }
74
75  if (BuildSinks)
76    C.generateSink(CE);
77}
78
79void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
80  mgr.registerChecker<NoReturnFunctionChecker>();
81}
82