181ad6265SDimitry Andric //=== ErrnoTesterChecker.cpp ------------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This defines ErrnoTesterChecker, which is used to test functionality of the 1081ad6265SDimitry Andric // errno_check API. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "ErrnoModeling.h" 1581ad6265SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 1681ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 1781ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 1881ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 1981ad6265SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20bdd1243dSDimitry Andric #include <optional> 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric using namespace clang; 2381ad6265SDimitry Andric using namespace ento; 2481ad6265SDimitry Andric using namespace errno_modeling; 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric namespace { 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric class ErrnoTesterChecker : public Checker<eval::Call> { 2981ad6265SDimitry Andric public: 3081ad6265SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric private: 3381ad6265SDimitry Andric /// Evaluate function \code void ErrnoTesterChecker_setErrno(int) \endcode. 3481ad6265SDimitry Andric /// Set value of \c errno to the argument. 3581ad6265SDimitry Andric static void evalSetErrno(CheckerContext &C, const CallEvent &Call); 3681ad6265SDimitry Andric /// Evaluate function \code int ErrnoTesterChecker_getErrno() \endcode. 3781ad6265SDimitry Andric /// Return the value of \c errno. 3881ad6265SDimitry Andric static void evalGetErrno(CheckerContext &C, const CallEvent &Call); 3981ad6265SDimitry Andric /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfError() \endcode. 4081ad6265SDimitry Andric /// Simulate a standard library function tha returns 0 on success and 1 on 4181ad6265SDimitry Andric /// failure. On the success case \c errno is not allowed to be used (may be 4281ad6265SDimitry Andric /// undefined). On the failure case \c errno is set to a fixed value 11 and 4381ad6265SDimitry Andric /// is not needed to be checked. 4481ad6265SDimitry Andric static void evalSetErrnoIfError(CheckerContext &C, const CallEvent &Call); 4581ad6265SDimitry Andric /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfErrorRange() 4681ad6265SDimitry Andric /// \endcode. Same as \c ErrnoTesterChecker_setErrnoIfError but \c errno is 4781ad6265SDimitry Andric /// set to a range (to be nonzero) at the failure case. 4881ad6265SDimitry Andric static void evalSetErrnoIfErrorRange(CheckerContext &C, 4981ad6265SDimitry Andric const CallEvent &Call); 5081ad6265SDimitry Andric /// Evaluate function \code int ErrnoTesterChecker_setErrnoCheckState() 5181ad6265SDimitry Andric /// \endcode. This function simulates the following: 5281ad6265SDimitry Andric /// - Return 0 and leave \c errno with undefined value. 5381ad6265SDimitry Andric /// This is the case of a successful standard function call. 5481ad6265SDimitry Andric /// For example if \c ftell returns not -1. 5581ad6265SDimitry Andric /// - Return 1 and sets \c errno to a specific error code (1). 5681ad6265SDimitry Andric /// This is the case of a failed standard function call. 5781ad6265SDimitry Andric /// The function indicates the failure by a special return value 5881ad6265SDimitry Andric /// that is returned only at failure. 5981ad6265SDimitry Andric /// \c errno can be checked but it is not required. 6081ad6265SDimitry Andric /// For example if \c ftell returns -1. 6181ad6265SDimitry Andric /// - Return 2 and may set errno to a value (actually it does not set it). 6281ad6265SDimitry Andric /// This is the case of a standard function call where the failure can only 6381ad6265SDimitry Andric /// be checked by reading from \c errno. The value of \c errno is changed by 6481ad6265SDimitry Andric /// the function only at failure, the user should set \c errno to 0 before 6581ad6265SDimitry Andric /// the call (\c ErrnoChecker does not check for this rule). 6681ad6265SDimitry Andric /// \c strtol is an example of this case, if it returns \c LONG_MIN (or 6781ad6265SDimitry Andric /// \c LONG_MAX). This case applies only if \c LONG_MIN or \c LONG_MAX is 6881ad6265SDimitry Andric /// returned, otherwise the first case in this list applies. 6981ad6265SDimitry Andric static void evalSetErrnoCheckState(CheckerContext &C, const CallEvent &Call); 7081ad6265SDimitry Andric 7181ad6265SDimitry Andric using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>; 7281ad6265SDimitry Andric const CallDescriptionMap<EvalFn> TestCalls{ 73*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrno"}, 1}, 74*0fca6ea1SDimitry Andric &ErrnoTesterChecker::evalSetErrno}, 75*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"ErrnoTesterChecker_getErrno"}, 0}, 76*0fca6ea1SDimitry Andric &ErrnoTesterChecker::evalGetErrno}, 77*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfError"}, 0}, 7881ad6265SDimitry Andric &ErrnoTesterChecker::evalSetErrnoIfError}, 79*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0}, 8081ad6265SDimitry Andric &ErrnoTesterChecker::evalSetErrnoIfErrorRange}, 81*0fca6ea1SDimitry Andric {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoCheckState"}, 0}, 8281ad6265SDimitry Andric &ErrnoTesterChecker::evalSetErrnoCheckState}}; 8381ad6265SDimitry Andric }; 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric } // namespace 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrno(CheckerContext &C, 8881ad6265SDimitry Andric const CallEvent &Call) { 8981ad6265SDimitry Andric C.addTransition(setErrnoValue(C.getState(), C.getLocationContext(), 9081ad6265SDimitry Andric Call.getArgSVal(0), Irrelevant)); 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric void ErrnoTesterChecker::evalGetErrno(CheckerContext &C, 9481ad6265SDimitry Andric const CallEvent &Call) { 9581ad6265SDimitry Andric ProgramStateRef State = C.getState(); 9681ad6265SDimitry Andric 97bdd1243dSDimitry Andric std::optional<SVal> ErrnoVal = getErrnoValue(State); 9881ad6265SDimitry Andric assert(ErrnoVal && "Errno value should be available."); 9981ad6265SDimitry Andric State = 10081ad6265SDimitry Andric State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal); 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric C.addTransition(State); 10381ad6265SDimitry Andric } 10481ad6265SDimitry Andric 10581ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoIfError(CheckerContext &C, 10681ad6265SDimitry Andric const CallEvent &Call) { 10781ad6265SDimitry Andric ProgramStateRef State = C.getState(); 10881ad6265SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric ProgramStateRef StateSuccess = State->BindExpr( 11181ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 11281ad6265SDimitry Andric StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric ProgramStateRef StateFailure = State->BindExpr( 11581ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 11681ad6265SDimitry Andric StateFailure = setErrnoValue(StateFailure, C, 11, Irrelevant); 11781ad6265SDimitry Andric 11881ad6265SDimitry Andric C.addTransition(StateSuccess); 11981ad6265SDimitry Andric C.addTransition(StateFailure); 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C, 12381ad6265SDimitry Andric const CallEvent &Call) { 12481ad6265SDimitry Andric ProgramStateRef State = C.getState(); 12581ad6265SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 12681ad6265SDimitry Andric 12781ad6265SDimitry Andric ProgramStateRef StateSuccess = State->BindExpr( 12881ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 12981ad6265SDimitry Andric StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric ProgramStateRef StateFailure = State->BindExpr( 13281ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 13381ad6265SDimitry Andric DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal( 13481ad6265SDimitry Andric nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount()); 13581ad6265SDimitry Andric StateFailure = StateFailure->assume(ErrnoVal, true); 13681ad6265SDimitry Andric assert(StateFailure && "Failed to assume on an initial value."); 13781ad6265SDimitry Andric StateFailure = 13881ad6265SDimitry Andric setErrnoValue(StateFailure, C.getLocationContext(), ErrnoVal, Irrelevant); 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric C.addTransition(StateSuccess); 14181ad6265SDimitry Andric C.addTransition(StateFailure); 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric 14481ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoCheckState(CheckerContext &C, 14581ad6265SDimitry Andric const CallEvent &Call) { 14681ad6265SDimitry Andric ProgramStateRef State = C.getState(); 14781ad6265SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric ProgramStateRef StateSuccess = State->BindExpr( 15081ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true)); 15181ad6265SDimitry Andric StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked); 15281ad6265SDimitry Andric 15381ad6265SDimitry Andric ProgramStateRef StateFailure1 = State->BindExpr( 15481ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true)); 15581ad6265SDimitry Andric StateFailure1 = setErrnoValue(StateFailure1, C, 1, Irrelevant); 15681ad6265SDimitry Andric 15781ad6265SDimitry Andric ProgramStateRef StateFailure2 = State->BindExpr( 15881ad6265SDimitry Andric Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(2, true)); 15981ad6265SDimitry Andric StateFailure2 = setErrnoValue(StateFailure2, C, 2, MustBeChecked); 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric C.addTransition(StateSuccess, 16281ad6265SDimitry Andric getErrnoNoteTag(C, "Assuming that this function succeeds but " 16381ad6265SDimitry Andric "sets 'errno' to an unspecified value.")); 16481ad6265SDimitry Andric C.addTransition(StateFailure1); 16581ad6265SDimitry Andric C.addTransition( 16681ad6265SDimitry Andric StateFailure2, 16781ad6265SDimitry Andric getErrnoNoteTag(C, "Assuming that this function returns 2. 'errno' " 16881ad6265SDimitry Andric "should be checked to test for failure.")); 16981ad6265SDimitry Andric } 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric bool ErrnoTesterChecker::evalCall(const CallEvent &Call, 17281ad6265SDimitry Andric CheckerContext &C) const { 17381ad6265SDimitry Andric const EvalFn *Fn = TestCalls.lookup(Call); 17481ad6265SDimitry Andric if (Fn) { 17581ad6265SDimitry Andric (*Fn)(C, Call); 17681ad6265SDimitry Andric return C.isDifferent(); 17781ad6265SDimitry Andric } 17881ad6265SDimitry Andric return false; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 18181ad6265SDimitry Andric void ento::registerErrnoTesterChecker(CheckerManager &Mgr) { 18281ad6265SDimitry Andric Mgr.registerChecker<ErrnoTesterChecker>(); 18381ad6265SDimitry Andric } 18481ad6265SDimitry Andric 18581ad6265SDimitry Andric bool ento::shouldRegisterErrnoTesterChecker(const CheckerManager &Mgr) { 18681ad6265SDimitry Andric return true; 18781ad6265SDimitry Andric } 188