xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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