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