1239313Sdim//==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==// 2239313Sdim// 3239313Sdim// The LLVM Compiler Infrastructure 4239313Sdim// 5239313Sdim// This file is distributed under the University of Illinois Open Source 6239313Sdim// License. See LICENSE.TXT for details. 7239313Sdim// 8239313Sdim//===----------------------------------------------------------------------===// 9239313Sdim 10239313Sdim#include "ClangSACheckers.h" 11249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 12239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 13239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 14249423Sdim#include "llvm/ADT/StringSwitch.h" 15239313Sdim 16239313Sdimusing namespace clang; 17239313Sdimusing namespace ento; 18239313Sdim 19239313Sdimnamespace { 20239313Sdimclass ExprInspectionChecker : public Checker< eval::Call > { 21239313Sdim mutable OwningPtr<BugType> BT; 22239313Sdim 23239313Sdim void analyzerEval(const CallExpr *CE, CheckerContext &C) const; 24239313Sdim void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; 25263508Sdim void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const; 26263508Sdim void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; 27239313Sdim 28239313Sdim typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, 29239313Sdim CheckerContext &C) const; 30239313Sdim 31239313Sdimpublic: 32239313Sdim bool evalCall(const CallExpr *CE, CheckerContext &C) const; 33239313Sdim}; 34239313Sdim} 35239313Sdim 36239313Sdimbool ExprInspectionChecker::evalCall(const CallExpr *CE, 37239313Sdim CheckerContext &C) const { 38239313Sdim // These checks should have no effect on the surrounding environment 39239313Sdim // (globals should not be invalidated, etc), hence the use of evalCall. 40239313Sdim FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE)) 41239313Sdim .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) 42239313Sdim .Case("clang_analyzer_checkInlined", 43239313Sdim &ExprInspectionChecker::analyzerCheckInlined) 44263508Sdim .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) 45263508Sdim .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached) 46239313Sdim .Default(0); 47239313Sdim 48239313Sdim if (!Handler) 49239313Sdim return false; 50239313Sdim 51239313Sdim (this->*Handler)(CE, C); 52239313Sdim return true; 53239313Sdim} 54239313Sdim 55239313Sdimstatic const char *getArgumentValueString(const CallExpr *CE, 56239313Sdim CheckerContext &C) { 57239313Sdim if (CE->getNumArgs() == 0) 58239313Sdim return "Missing assertion argument"; 59239313Sdim 60239313Sdim ExplodedNode *N = C.getPredecessor(); 61239313Sdim const LocationContext *LC = N->getLocationContext(); 62239313Sdim ProgramStateRef State = N->getState(); 63239313Sdim 64239313Sdim const Expr *Assertion = CE->getArg(0); 65239313Sdim SVal AssertionVal = State->getSVal(Assertion, LC); 66239313Sdim 67239313Sdim if (AssertionVal.isUndef()) 68239313Sdim return "UNDEFINED"; 69239313Sdim 70239313Sdim ProgramStateRef StTrue, StFalse; 71239313Sdim llvm::tie(StTrue, StFalse) = 72249423Sdim State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>()); 73239313Sdim 74239313Sdim if (StTrue) { 75239313Sdim if (StFalse) 76239313Sdim return "UNKNOWN"; 77239313Sdim else 78239313Sdim return "TRUE"; 79239313Sdim } else { 80239313Sdim if (StFalse) 81239313Sdim return "FALSE"; 82239313Sdim else 83239313Sdim llvm_unreachable("Invalid constraint; neither true or false."); 84239313Sdim } 85239313Sdim} 86239313Sdim 87239313Sdimvoid ExprInspectionChecker::analyzerEval(const CallExpr *CE, 88239313Sdim CheckerContext &C) const { 89239313Sdim ExplodedNode *N = C.getPredecessor(); 90239313Sdim const LocationContext *LC = N->getLocationContext(); 91239313Sdim 92239313Sdim // A specific instantiation of an inlined function may have more constrained 93239313Sdim // values than can generally be assumed. Skip the check. 94239313Sdim if (LC->getCurrentStackFrame()->getParent() != 0) 95239313Sdim return; 96239313Sdim 97239313Sdim if (!BT) 98239313Sdim BT.reset(new BugType("Checking analyzer assumptions", "debug")); 99239313Sdim 100239313Sdim BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); 101243830Sdim C.emitReport(R); 102239313Sdim} 103239313Sdim 104263508Sdimvoid ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, 105263508Sdim CheckerContext &C) const { 106263508Sdim ExplodedNode *N = C.getPredecessor(); 107263508Sdim 108263508Sdim if (!BT) 109263508Sdim BT.reset(new BugType("Checking analyzer assumptions", "debug")); 110263508Sdim 111263508Sdim BugReport *R = new BugReport(*BT, "REACHABLE", N); 112263508Sdim C.emitReport(R); 113263508Sdim} 114263508Sdim 115239313Sdimvoid ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, 116239313Sdim CheckerContext &C) const { 117239313Sdim ExplodedNode *N = C.getPredecessor(); 118239313Sdim const LocationContext *LC = N->getLocationContext(); 119239313Sdim 120239313Sdim // An inlined function could conceivably also be analyzed as a top-level 121239313Sdim // function. We ignore this case and only emit a message (TRUE or FALSE) 122239313Sdim // when we are analyzing it as an inlined function. This means that 123239313Sdim // clang_analyzer_checkInlined(true) should always print TRUE, but 124239313Sdim // clang_analyzer_checkInlined(false) should never actually print anything. 125239313Sdim if (LC->getCurrentStackFrame()->getParent() == 0) 126239313Sdim return; 127239313Sdim 128239313Sdim if (!BT) 129239313Sdim BT.reset(new BugType("Checking analyzer assumptions", "debug")); 130239313Sdim 131239313Sdim BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); 132243830Sdim C.emitReport(R); 133239313Sdim} 134239313Sdim 135263508Sdimvoid ExprInspectionChecker::analyzerCrash(const CallExpr *CE, 136263508Sdim CheckerContext &C) const { 137263508Sdim LLVM_BUILTIN_TRAP; 138263508Sdim} 139263508Sdim 140239313Sdimvoid ento::registerExprInspectionChecker(CheckerManager &Mgr) { 141239313Sdim Mgr.registerChecker<ExprInspectionChecker>(); 142239313Sdim} 143239313Sdim 144