xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp (revision e2f1cbae45f81f3cd9a4d3c2bcf69a094eb060fa)
1d8a2afb2SBalázs Kéri //=== ErrnoTesterChecker.cpp ------------------------------------*- C++ -*-===//
2d8a2afb2SBalázs Kéri //
3d8a2afb2SBalázs Kéri // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d8a2afb2SBalázs Kéri // See https://llvm.org/LICENSE.txt for license information.
5d8a2afb2SBalázs Kéri // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d8a2afb2SBalázs Kéri //
7d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
8d8a2afb2SBalázs Kéri //
9d8a2afb2SBalázs Kéri // This defines ErrnoTesterChecker, which is used to test functionality of the
10d8a2afb2SBalázs Kéri // errno_check API.
11d8a2afb2SBalázs Kéri //
12d8a2afb2SBalázs Kéri //===----------------------------------------------------------------------===//
13d8a2afb2SBalázs Kéri 
14d8a2afb2SBalázs Kéri #include "ErrnoModeling.h"
15d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/Checker.h"
17d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
19d8a2afb2SBalázs Kéri #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20a1580d7bSKazu Hirata #include <optional>
21d8a2afb2SBalázs Kéri 
22d8a2afb2SBalázs Kéri using namespace clang;
23d8a2afb2SBalázs Kéri using namespace ento;
2460f3b071SBalázs Kéri using namespace errno_modeling;
25d8a2afb2SBalázs Kéri 
26d8a2afb2SBalázs Kéri namespace {
27d8a2afb2SBalázs Kéri 
28d8a2afb2SBalázs Kéri class ErrnoTesterChecker : public Checker<eval::Call> {
29d8a2afb2SBalázs Kéri public:
30d8a2afb2SBalázs Kéri   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
31d8a2afb2SBalázs Kéri 
32d8a2afb2SBalázs Kéri private:
3360f3b071SBalázs Kéri   /// Evaluate function \code void ErrnoTesterChecker_setErrno(int) \endcode.
3460f3b071SBalázs Kéri   /// Set value of \c errno to the argument.
35d8a2afb2SBalázs Kéri   static void evalSetErrno(CheckerContext &C, const CallEvent &Call);
3660f3b071SBalázs Kéri   /// Evaluate function \code int ErrnoTesterChecker_getErrno() \endcode.
3760f3b071SBalázs Kéri   /// Return the value of \c errno.
38d8a2afb2SBalázs Kéri   static void evalGetErrno(CheckerContext &C, const CallEvent &Call);
3960f3b071SBalázs Kéri   /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfError() \endcode.
4060f3b071SBalázs Kéri   /// Simulate a standard library function tha returns 0 on success and 1 on
4160f3b071SBalázs Kéri   /// failure. On the success case \c errno is not allowed to be used (may be
4260f3b071SBalázs Kéri   /// undefined). On the failure case \c errno is set to a fixed value 11 and
4360f3b071SBalázs Kéri   /// is not needed to be checked.
44d8a2afb2SBalázs Kéri   static void evalSetErrnoIfError(CheckerContext &C, const CallEvent &Call);
4560f3b071SBalázs Kéri   /// Evaluate function \code int ErrnoTesterChecker_setErrnoIfErrorRange()
4660f3b071SBalázs Kéri   /// \endcode. Same as \c ErrnoTesterChecker_setErrnoIfError but \c errno is
4760f3b071SBalázs Kéri   /// set to a range (to be nonzero) at the failure case.
48d8a2afb2SBalázs Kéri   static void evalSetErrnoIfErrorRange(CheckerContext &C,
49d8a2afb2SBalázs Kéri                                        const CallEvent &Call);
5060f3b071SBalázs Kéri   /// Evaluate function \code int ErrnoTesterChecker_setErrnoCheckState()
5160f3b071SBalázs Kéri   /// \endcode. This function simulates the following:
5260f3b071SBalázs Kéri   /// - Return 0 and leave \c errno with undefined value.
5360f3b071SBalázs Kéri   ///   This is the case of a successful standard function call.
5460f3b071SBalázs Kéri   ///   For example if \c ftell returns not -1.
5560f3b071SBalázs Kéri   /// - Return 1 and sets \c errno to a specific error code (1).
5660f3b071SBalázs Kéri   ///   This is the case of a failed standard function call.
5760f3b071SBalázs Kéri   ///   The function indicates the failure by a special return value
5860f3b071SBalázs Kéri   ///   that is returned only at failure.
5960f3b071SBalázs Kéri   ///   \c errno can be checked but it is not required.
6060f3b071SBalázs Kéri   ///   For example if \c ftell returns -1.
6160f3b071SBalázs Kéri   /// - Return 2 and may set errno to a value (actually it does not set it).
6260f3b071SBalázs Kéri   ///   This is the case of a standard function call where the failure can only
6360f3b071SBalázs Kéri   ///   be checked by reading from \c errno. The value of \c errno is changed by
6460f3b071SBalázs Kéri   ///   the function only at failure, the user should set \c errno to 0 before
6560f3b071SBalázs Kéri   ///   the call (\c ErrnoChecker does not check for this rule).
6660f3b071SBalázs Kéri   ///   \c strtol is an example of this case, if it returns \c LONG_MIN (or
6760f3b071SBalázs Kéri   ///   \c LONG_MAX). This case applies only if \c LONG_MIN or \c LONG_MAX is
6860f3b071SBalázs Kéri   ///   returned, otherwise the first case in this list applies.
6960f3b071SBalázs Kéri   static void evalSetErrnoCheckState(CheckerContext &C, const CallEvent &Call);
70d8a2afb2SBalázs Kéri 
71d8a2afb2SBalázs Kéri   using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>;
72d8a2afb2SBalázs Kéri   const CallDescriptionMap<EvalFn> TestCalls{
73*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrno"}, 1},
74*e2f1cbaeSNagyDonat        &ErrnoTesterChecker::evalSetErrno},
75*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"ErrnoTesterChecker_getErrno"}, 0},
76*e2f1cbaeSNagyDonat        &ErrnoTesterChecker::evalGetErrno},
77*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfError"}, 0},
78d8a2afb2SBalázs Kéri        &ErrnoTesterChecker::evalSetErrnoIfError},
79*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
8060f3b071SBalázs Kéri        &ErrnoTesterChecker::evalSetErrnoIfErrorRange},
81*e2f1cbaeSNagyDonat       {{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoCheckState"}, 0},
8260f3b071SBalázs Kéri        &ErrnoTesterChecker::evalSetErrnoCheckState}};
83d8a2afb2SBalázs Kéri };
84d8a2afb2SBalázs Kéri 
85d8a2afb2SBalázs Kéri } // namespace
86d8a2afb2SBalázs Kéri 
evalSetErrno(CheckerContext & C,const CallEvent & Call)87d8a2afb2SBalázs Kéri void ErrnoTesterChecker::evalSetErrno(CheckerContext &C,
88d8a2afb2SBalázs Kéri                                       const CallEvent &Call) {
8960f3b071SBalázs Kéri   C.addTransition(setErrnoValue(C.getState(), C.getLocationContext(),
9060f3b071SBalázs Kéri                                 Call.getArgSVal(0), Irrelevant));
91d8a2afb2SBalázs Kéri }
92d8a2afb2SBalázs Kéri 
evalGetErrno(CheckerContext & C,const CallEvent & Call)93d8a2afb2SBalázs Kéri void ErrnoTesterChecker::evalGetErrno(CheckerContext &C,
94d8a2afb2SBalázs Kéri                                       const CallEvent &Call) {
95d8a2afb2SBalázs Kéri   ProgramStateRef State = C.getState();
96d8a2afb2SBalázs Kéri 
976ad0788cSKazu Hirata   std::optional<SVal> ErrnoVal = getErrnoValue(State);
98d8a2afb2SBalázs Kéri   assert(ErrnoVal && "Errno value should be available.");
99d8a2afb2SBalázs Kéri   State =
100d8a2afb2SBalázs Kéri       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal);
101d8a2afb2SBalázs Kéri 
102d8a2afb2SBalázs Kéri   C.addTransition(State);
103d8a2afb2SBalázs Kéri }
104d8a2afb2SBalázs Kéri 
evalSetErrnoIfError(CheckerContext & C,const CallEvent & Call)105d8a2afb2SBalázs Kéri void ErrnoTesterChecker::evalSetErrnoIfError(CheckerContext &C,
106d8a2afb2SBalázs Kéri                                              const CallEvent &Call) {
107d8a2afb2SBalázs Kéri   ProgramStateRef State = C.getState();
108d8a2afb2SBalázs Kéri   SValBuilder &SVB = C.getSValBuilder();
109d8a2afb2SBalázs Kéri 
110d8a2afb2SBalázs Kéri   ProgramStateRef StateSuccess = State->BindExpr(
111d8a2afb2SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
11260f3b071SBalázs Kéri   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
113d8a2afb2SBalázs Kéri 
114d8a2afb2SBalázs Kéri   ProgramStateRef StateFailure = State->BindExpr(
115d8a2afb2SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
11660f3b071SBalázs Kéri   StateFailure = setErrnoValue(StateFailure, C, 11, Irrelevant);
117d8a2afb2SBalázs Kéri 
118d8a2afb2SBalázs Kéri   C.addTransition(StateSuccess);
119d8a2afb2SBalázs Kéri   C.addTransition(StateFailure);
120d8a2afb2SBalázs Kéri }
121d8a2afb2SBalázs Kéri 
evalSetErrnoIfErrorRange(CheckerContext & C,const CallEvent & Call)122d8a2afb2SBalázs Kéri void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,
123d8a2afb2SBalázs Kéri                                                   const CallEvent &Call) {
124d8a2afb2SBalázs Kéri   ProgramStateRef State = C.getState();
125d8a2afb2SBalázs Kéri   SValBuilder &SVB = C.getSValBuilder();
126d8a2afb2SBalázs Kéri 
127d8a2afb2SBalázs Kéri   ProgramStateRef StateSuccess = State->BindExpr(
128d8a2afb2SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
12960f3b071SBalázs Kéri   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
130d8a2afb2SBalázs Kéri 
131d8a2afb2SBalázs Kéri   ProgramStateRef StateFailure = State->BindExpr(
132d8a2afb2SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
133d8a2afb2SBalázs Kéri   DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(
134d8a2afb2SBalázs Kéri       nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount());
135d8a2afb2SBalázs Kéri   StateFailure = StateFailure->assume(ErrnoVal, true);
136d8a2afb2SBalázs Kéri   assert(StateFailure && "Failed to assume on an initial value.");
13760f3b071SBalázs Kéri   StateFailure =
13860f3b071SBalázs Kéri       setErrnoValue(StateFailure, C.getLocationContext(), ErrnoVal, Irrelevant);
139d8a2afb2SBalázs Kéri 
140d8a2afb2SBalázs Kéri   C.addTransition(StateSuccess);
141d8a2afb2SBalázs Kéri   C.addTransition(StateFailure);
142d8a2afb2SBalázs Kéri }
143d8a2afb2SBalázs Kéri 
evalSetErrnoCheckState(CheckerContext & C,const CallEvent & Call)14460f3b071SBalázs Kéri void ErrnoTesterChecker::evalSetErrnoCheckState(CheckerContext &C,
14560f3b071SBalázs Kéri                                                 const CallEvent &Call) {
14660f3b071SBalázs Kéri   ProgramStateRef State = C.getState();
14760f3b071SBalázs Kéri   SValBuilder &SVB = C.getSValBuilder();
14860f3b071SBalázs Kéri 
14960f3b071SBalázs Kéri   ProgramStateRef StateSuccess = State->BindExpr(
15060f3b071SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
15160f3b071SBalázs Kéri   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
15260f3b071SBalázs Kéri 
15360f3b071SBalázs Kéri   ProgramStateRef StateFailure1 = State->BindExpr(
15460f3b071SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
15560f3b071SBalázs Kéri   StateFailure1 = setErrnoValue(StateFailure1, C, 1, Irrelevant);
15660f3b071SBalázs Kéri 
15760f3b071SBalázs Kéri   ProgramStateRef StateFailure2 = State->BindExpr(
15860f3b071SBalázs Kéri       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(2, true));
15960f3b071SBalázs Kéri   StateFailure2 = setErrnoValue(StateFailure2, C, 2, MustBeChecked);
16060f3b071SBalázs Kéri 
16160f3b071SBalázs Kéri   C.addTransition(StateSuccess,
16260f3b071SBalázs Kéri                   getErrnoNoteTag(C, "Assuming that this function succeeds but "
16360f3b071SBalázs Kéri                                      "sets 'errno' to an unspecified value."));
16460f3b071SBalázs Kéri   C.addTransition(StateFailure1);
16560f3b071SBalázs Kéri   C.addTransition(
16660f3b071SBalázs Kéri       StateFailure2,
16760f3b071SBalázs Kéri       getErrnoNoteTag(C, "Assuming that this function returns 2. 'errno' "
16860f3b071SBalázs Kéri                          "should be checked to test for failure."));
16960f3b071SBalázs Kéri }
17060f3b071SBalázs Kéri 
evalCall(const CallEvent & Call,CheckerContext & C) const171d8a2afb2SBalázs Kéri bool ErrnoTesterChecker::evalCall(const CallEvent &Call,
172d8a2afb2SBalázs Kéri                                   CheckerContext &C) const {
173d8a2afb2SBalázs Kéri   const EvalFn *Fn = TestCalls.lookup(Call);
174d8a2afb2SBalázs Kéri   if (Fn) {
175d8a2afb2SBalázs Kéri     (*Fn)(C, Call);
176d8a2afb2SBalázs Kéri     return C.isDifferent();
177d8a2afb2SBalázs Kéri   }
178d8a2afb2SBalázs Kéri   return false;
179d8a2afb2SBalázs Kéri }
180d8a2afb2SBalázs Kéri 
registerErrnoTesterChecker(CheckerManager & Mgr)181d8a2afb2SBalázs Kéri void ento::registerErrnoTesterChecker(CheckerManager &Mgr) {
182d8a2afb2SBalázs Kéri   Mgr.registerChecker<ErrnoTesterChecker>();
183d8a2afb2SBalázs Kéri }
184d8a2afb2SBalázs Kéri 
shouldRegisterErrnoTesterChecker(const CheckerManager & Mgr)185d8a2afb2SBalázs Kéri bool ento::shouldRegisterErrnoTesterChecker(const CheckerManager &Mgr) {
186d8a2afb2SBalázs Kéri   return true;
187d8a2afb2SBalázs Kéri }
188