1//==- ExprInspectionChecker.cpp - Used for regression tests ------*- 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#include "ClangSACheckers.h" 11#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 12#include "clang/StaticAnalyzer/Core/Checker.h" 13#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 14#include "llvm/ADT/StringSwitch.h" 15 16using namespace clang; 17using namespace ento; 18 19namespace { 20class ExprInspectionChecker : public Checker< eval::Call > { 21 mutable OwningPtr<BugType> BT; 22 23 void analyzerEval(const CallExpr *CE, CheckerContext &C) const; 24 void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; 25 void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; 26 27 typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, 28 CheckerContext &C) const; 29 30public: 31 bool evalCall(const CallExpr *CE, CheckerContext &C) const; 32}; 33} 34 35bool ExprInspectionChecker::evalCall(const CallExpr *CE, 36 CheckerContext &C) const { 37 // These checks should have no effect on the surrounding environment 38 // (globals should not be invalidated, etc), hence the use of evalCall. 39 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE)) 40 .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) 41 .Case("clang_analyzer_checkInlined", 42 &ExprInspectionChecker::analyzerCheckInlined) 43 .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) 44 .Default(0); 45 46 if (!Handler) 47 return false; 48 49 (this->*Handler)(CE, C); 50 return true; 51} 52 53static const char *getArgumentValueString(const CallExpr *CE, 54 CheckerContext &C) { 55 if (CE->getNumArgs() == 0) 56 return "Missing assertion argument"; 57 58 ExplodedNode *N = C.getPredecessor(); 59 const LocationContext *LC = N->getLocationContext(); 60 ProgramStateRef State = N->getState(); 61 62 const Expr *Assertion = CE->getArg(0); 63 SVal AssertionVal = State->getSVal(Assertion, LC); 64 65 if (AssertionVal.isUndef()) 66 return "UNDEFINED"; 67 68 ProgramStateRef StTrue, StFalse; 69 llvm::tie(StTrue, StFalse) = 70 State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>()); 71 72 if (StTrue) { 73 if (StFalse) 74 return "UNKNOWN"; 75 else 76 return "TRUE"; 77 } else { 78 if (StFalse) 79 return "FALSE"; 80 else 81 llvm_unreachable("Invalid constraint; neither true or false."); 82 } 83} 84 85void ExprInspectionChecker::analyzerEval(const CallExpr *CE, 86 CheckerContext &C) const { 87 ExplodedNode *N = C.getPredecessor(); 88 const LocationContext *LC = N->getLocationContext(); 89 90 // A specific instantiation of an inlined function may have more constrained 91 // values than can generally be assumed. Skip the check. 92 if (LC->getCurrentStackFrame()->getParent() != 0) 93 return; 94 95 if (!BT) 96 BT.reset(new BugType("Checking analyzer assumptions", "debug")); 97 98 BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); 99 C.emitReport(R); 100} 101 102void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, 103 CheckerContext &C) const { 104 ExplodedNode *N = C.getPredecessor(); 105 const LocationContext *LC = N->getLocationContext(); 106 107 // An inlined function could conceivably also be analyzed as a top-level 108 // function. We ignore this case and only emit a message (TRUE or FALSE) 109 // when we are analyzing it as an inlined function. This means that 110 // clang_analyzer_checkInlined(true) should always print TRUE, but 111 // clang_analyzer_checkInlined(false) should never actually print anything. 112 if (LC->getCurrentStackFrame()->getParent() == 0) 113 return; 114 115 if (!BT) 116 BT.reset(new BugType("Checking analyzer assumptions", "debug")); 117 118 BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); 119 C.emitReport(R); 120} 121 122void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, 123 CheckerContext &C) const { 124 LLVM_BUILTIN_TRAP; 125} 126 127void ento::registerExprInspectionChecker(CheckerManager &Mgr) { 128 Mgr.registerChecker<ExprInspectionChecker>(); 129} 130 131