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