193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
293a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//
393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//                     The LLVM Compiler Infrastructure
493a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//
593a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose// This file is distributed under the University of Illinois Open Source
693a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose// License. See LICENSE.TXT for details.
793a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//
893a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose//===----------------------------------------------------------------------===//
993a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
1093a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose#include "ClangSACheckers.h"
1193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1255fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h"
1393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
149852f58f50b4fc20914fbce5b4454135a42343f4Benjamin Kramer#include "llvm/ADT/StringSwitch.h"
1593a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
1693a9d828378b5c969344f27aeb275b8c2a19d918Jordy Roseusing namespace clang;
1793a9d828378b5c969344f27aeb275b8c2a19d918Jordy Roseusing namespace ento;
1893a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
1993a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rosenamespace {
2093a9d828378b5c969344f27aeb275b8c2a19d918Jordy Roseclass ExprInspectionChecker : public Checker< eval::Call > {
21651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  mutable std::unique_ptr<BugType> BT;
22e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
23e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
24e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
25d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose  void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
26ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose  void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
27e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
28e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
29e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose                                                 CheckerContext &C) const;
30e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
3193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rosepublic:
3293a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
3393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose};
3493a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose}
3593a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
3693a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rosebool ExprInspectionChecker::evalCall(const CallExpr *CE,
37e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose                                     CheckerContext &C) const {
3893a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  // These checks should have no effect on the surrounding environment
39e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // (globals should not be invalidated, etc), hence the use of evalCall.
40e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
41e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
42e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    .Case("clang_analyzer_checkInlined",
43e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose          &ExprInspectionChecker::analyzerCheckInlined)
44ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose    .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
45d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose    .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    .Default(nullptr);
47e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
48e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  if (!Handler)
49e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    return false;
50e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
51e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  (this->*Handler)(CE, C);
52e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  return true;
53e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose}
54e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
55e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rosestatic const char *getArgumentValueString(const CallExpr *CE,
56e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose                                          CheckerContext &C) {
57e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  if (CE->getNumArgs() == 0)
58e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    return "Missing assertion argument";
59e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
6093a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  ExplodedNode *N = C.getPredecessor();
6193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  const LocationContext *LC = N->getLocationContext();
62e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  ProgramStateRef State = N->getState();
63e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
64e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  const Expr *Assertion = CE->getArg(0);
65e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  SVal AssertionVal = State->getSVal(Assertion, LC);
66e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
67e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  if (AssertionVal.isUndef())
68e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    return "UNDEFINED";
69e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
70e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  ProgramStateRef StTrue, StFalse;
71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::tie(StTrue, StFalse) =
725251abea41b446c26e3239c8dd6c7edea6fc335dDavid Blaikie    State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
73e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
74e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  if (StTrue) {
75e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    if (StFalse)
76e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose      return "UNKNOWN";
77e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    else
78e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose      return "TRUE";
79e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  } else {
80e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    if (StFalse)
81e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose      return "FALSE";
82e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    else
83e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose      llvm_unreachable("Invalid constraint; neither true or false.");
84e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  }
85e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose}
8693a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
87e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rosevoid ExprInspectionChecker::analyzerEval(const CallExpr *CE,
88e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose                                         CheckerContext &C) const {
89e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  ExplodedNode *N = C.getPredecessor();
90e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  const LocationContext *LC = N->getLocationContext();
9193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
9293a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  // A specific instantiation of an inlined function may have more constrained
9393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  // values than can generally be assumed. Skip the check.
946bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (LC->getCurrentStackFrame()->getParent() != nullptr)
95e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    return;
9693a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
97e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  if (!BT)
98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
9993a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
100e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
101785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose  C.emitReport(R);
102e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose}
103e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose
104d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rosevoid ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
105d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose                                                  CheckerContext &C) const {
106d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose  ExplodedNode *N = C.getPredecessor();
107d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose
108d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose  if (!BT)
109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
110d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose
111d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose  BugReport *R = new BugReport(*BT, "REACHABLE", N);
112d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose  C.emitReport(R);
113d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose}
114d000b852022bcd4fc14029b48d2fa873f63e4032Jordan Rose
115e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rosevoid ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
116e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose                                                 CheckerContext &C) const {
117e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  ExplodedNode *N = C.getPredecessor();
118e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  const LocationContext *LC = N->getLocationContext();
11993a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
120e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // An inlined function could conceivably also be analyzed as a top-level
121e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // function. We ignore this case and only emit a message (TRUE or FALSE)
122e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // when we are analyzing it as an inlined function. This means that
123e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // clang_analyzer_checkInlined(true) should always print TRUE, but
124e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  // clang_analyzer_checkInlined(false) should never actually print anything.
1256bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (LC->getCurrentStackFrame()->getParent() == nullptr)
126e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose    return;
12793a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
12893a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  if (!BT)
129651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
13093a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
131e5399f1375f8571bdd821ae08291af1c895adfd3Jordan Rose  BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
132785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose  C.emitReport(R);
13393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose}
13493a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
135ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rosevoid ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
136ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose                                          CheckerContext &C) const {
137ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose  LLVM_BUILTIN_TRAP;
138ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose}
139ac7cc2d37e82181e73fcc265c1d0a619d18b7605Jordan Rose
14093a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rosevoid ento::registerExprInspectionChecker(CheckerManager &Mgr) {
14193a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose  Mgr.registerChecker<ExprInspectionChecker>();
14293a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose}
14393a9d828378b5c969344f27aeb275b8c2a19d918Jordy Rose
144