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