1 //=== ErrnoTesterChecker.cpp ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This defines ErrnoTesterChecker, which is used to test functionality of the 10 // errno_check API. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ErrnoModeling.h" 15 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 16 #include "clang/StaticAnalyzer/Core/Checker.h" 17 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 18 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20 21 using namespace clang; 22 using namespace ento; 23 using namespace errno_modeling; 24 25 namespace { 26 27 class ErrnoTesterChecker : public Checker<eval::Call> { 28 public: 29 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 30 31 private: 32 /// Evaluate function \code void ErrnoTesterChecker_setErrno(int) \endcode. 33 /// Set value of \c errno to the argument. 34 static void evalSetErrno(CheckerContext &C, const CallEvent &Call); 35 /// Evaluate function \code int ErrnoTesterChecker_getErrno() \endcode. 36 /// Return the value of \c errno. 37 static void evalGetErrno(CheckerContext &C, const CallEvent &Call); 38 /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfError() \endcode. 39 /// Simulate a standard library function tha returns 0 on success and 1 on 40 /// failure. On the success case \c errno is not allowed to be used (may be 41 /// undefined). On the failure case \c errno is set to a fixed value 11 and 42 /// is not needed to be checked. 43 static void evalSetErrnoIfError(CheckerContext &C, const CallEvent &Call); 44 /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfErrorRange() 45 /// \endcode. Same as \c ErrnoTesterChecker_setErrnoIfError but \c errno is 46 /// set to a range (to be nonzero) at the failure case. 47 static void evalSetErrnoIfErrorRange(CheckerContext &C, 48 const CallEvent &Call); 49 /// Evaluate function \code int ErrnoTesterChecker_setErrnoCheckState() 50 /// \endcode. This function simulates the following: 51 /// - Return 0 and leave \c errno with undefined value. 52 /// This is the case of a successful standard function call. 53 /// For example if \c ftell returns not -1. 54 /// - Return 1 and sets \c errno to a specific error code (1). 55 /// This is the case of a failed standard function call. 56 /// The function indicates the failure by a special return value 57 /// that is returned only at failure. 58 /// \c errno can be checked but it is not required. 59 /// For example if \c ftell returns -1. 60 /// - Return 2 and may set errno to a value (actually it does not set it). 61 /// This is the case of a standard function call where the failure can only 62 /// be checked by reading from \c errno. The value of \c errno is changed by 63 /// the function only at failure, the user should set \c errno to 0 before 64 /// the call (\c ErrnoChecker does not check for this rule). 65 /// \c strtol is an example of this case, if it returns \c LONG_MIN (or 66 /// \c LONG_MAX). This case applies only if \c LONG_MIN or \c LONG_MAX is 67 /// returned, otherwise the first case in this list applies. 68 static void evalSetErrnoCheckState(CheckerContext &C, const CallEvent &Call); 69 70 using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>; 71 const CallDescriptionMap<EvalFn> TestCalls{ 72 {{"ErrnoTesterChecker_setErrno", 1}, &ErrnoTesterChecker::evalSetErrno}, 73 {{"ErrnoTesterChecker_getErrno", 0}, &ErrnoTesterChecker::evalGetErrno}, 74 {{"ErrnoTesterChecker_setErrnoIfError", 0}, 75 &ErrnoTesterChecker::evalSetErrnoIfError}, 76 {{"ErrnoTesterChecker_setErrnoIfErrorRange", 0}, 77 &ErrnoTesterChecker::evalSetErrnoIfErrorRange}, 78 {{"ErrnoTesterChecker_setErrnoCheckState", 0}, 79 &ErrnoTesterChecker::evalSetErrnoCheckState}}; 80 }; 81 82 } // namespace 83 84 void ErrnoTesterChecker::evalSetErrno(CheckerContext &C, 85 const CallEvent &Call) { 86 C.addTransition(setErrnoValue(C.getState(), C.getLocationContext(), 87 Call.getArgSVal(0), Irrelevant)); 88 } 89 90 void ErrnoTesterChecker::evalGetErrno(CheckerContext &C, 91 const CallEvent &Call) { 92 ProgramStateRef State = C.getState(); 93 94 Optional<SVal> ErrnoVal = getErrnoValue(State); 95 assert(ErrnoVal && "Errno value should be available."); 96 State = 97 State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal); 98 99 C.addTransition(State); 100 } 101 102 void ErrnoTesterChecker::evalSetErrnoIfError(CheckerContext &C, 103 const CallEvent &Call) { 104 ProgramStateRef State = C.getState(); 105 SValBuilder &SVB = C.getSValBuilder(); 106 107 ProgramStateRef StateSuccess = State->BindExpr( 108 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 109 StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 110 111 ProgramStateRef StateFailure = State->BindExpr( 112 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 113 StateFailure = setErrnoValue(StateFailure, C, 11, Irrelevant); 114 115 C.addTransition(StateSuccess); 116 C.addTransition(StateFailure); 117 } 118 119 void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C, 120 const CallEvent &Call) { 121 ProgramStateRef State = C.getState(); 122 SValBuilder &SVB = C.getSValBuilder(); 123 124 ProgramStateRef StateSuccess = State->BindExpr( 125 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 126 StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 127 128 ProgramStateRef StateFailure = State->BindExpr( 129 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 130 DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal( 131 nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount()); 132 StateFailure = StateFailure->assume(ErrnoVal, true); 133 assert(StateFailure && "Failed to assume on an initial value."); 134 StateFailure = 135 setErrnoValue(StateFailure, C.getLocationContext(), ErrnoVal, Irrelevant); 136 137 C.addTransition(StateSuccess); 138 C.addTransition(StateFailure); 139 } 140 141 void ErrnoTesterChecker::evalSetErrnoCheckState(CheckerContext &C, 142 const CallEvent &Call) { 143 ProgramStateRef State = C.getState(); 144 SValBuilder &SVB = C.getSValBuilder(); 145 146 ProgramStateRef StateSuccess = State->BindExpr( 147 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 148 StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 149 150 ProgramStateRef StateFailure1 = State->BindExpr( 151 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 152 StateFailure1 = setErrnoValue(StateFailure1, C, 1, Irrelevant); 153 154 ProgramStateRef StateFailure2 = State->BindExpr( 155 Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(2, true)); 156 StateFailure2 = setErrnoValue(StateFailure2, C, 2, MustBeChecked); 157 158 C.addTransition(StateSuccess, 159 getErrnoNoteTag(C, "Assuming that this function succeeds but " 160 "sets 'errno' to an unspecified value.")); 161 C.addTransition(StateFailure1); 162 C.addTransition( 163 StateFailure2, 164 getErrnoNoteTag(C, "Assuming that this function returns 2. 'errno' " 165 "should be checked to test for failure.")); 166 } 167 168 bool ErrnoTesterChecker::evalCall(const CallEvent &Call, 169 CheckerContext &C) const { 170 const EvalFn *Fn = TestCalls.lookup(Call); 171 if (Fn) { 172 (*Fn)(C, Call); 173 return C.isDifferent(); 174 } 175 return false; 176 } 177 178 void ento::registerErrnoTesterChecker(CheckerManager &Mgr) { 179 Mgr.registerChecker<ErrnoTesterChecker>(); 180 } 181 182 bool ento::shouldRegisterErrnoTesterChecker(const CheckerManager &Mgr) { 183 return true; 184 } 185