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