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