xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
20*bdd1243dSDimitry 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*bdd1243dSDimitry Andric       {{{"ErrnoTesterChecker_setErrno"}, 1}, &ErrnoTesterChecker::evalSetErrno},
74*bdd1243dSDimitry Andric       {{{"ErrnoTesterChecker_getErrno"}, 0}, &ErrnoTesterChecker::evalGetErrno},
75*bdd1243dSDimitry Andric       {{{"ErrnoTesterChecker_setErrnoIfError"}, 0},
7681ad6265SDimitry Andric        &ErrnoTesterChecker::evalSetErrnoIfError},
77*bdd1243dSDimitry Andric       {{{"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
7881ad6265SDimitry Andric        &ErrnoTesterChecker::evalSetErrnoIfErrorRange},
79*bdd1243dSDimitry Andric       {{{"ErrnoTesterChecker_setErrnoCheckState"}, 0},
8081ad6265SDimitry Andric        &ErrnoTesterChecker::evalSetErrnoCheckState}};
8181ad6265SDimitry Andric };
8281ad6265SDimitry Andric 
8381ad6265SDimitry Andric } // namespace
8481ad6265SDimitry Andric 
8581ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrno(CheckerContext &C,
8681ad6265SDimitry Andric                                       const CallEvent &Call) {
8781ad6265SDimitry Andric   C.addTransition(setErrnoValue(C.getState(), C.getLocationContext(),
8881ad6265SDimitry Andric                                 Call.getArgSVal(0), Irrelevant));
8981ad6265SDimitry Andric }
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric void ErrnoTesterChecker::evalGetErrno(CheckerContext &C,
9281ad6265SDimitry Andric                                       const CallEvent &Call) {
9381ad6265SDimitry Andric   ProgramStateRef State = C.getState();
9481ad6265SDimitry Andric 
95*bdd1243dSDimitry Andric   std::optional<SVal> ErrnoVal = getErrnoValue(State);
9681ad6265SDimitry Andric   assert(ErrnoVal && "Errno value should be available.");
9781ad6265SDimitry Andric   State =
9881ad6265SDimitry Andric       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal);
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric   C.addTransition(State);
10181ad6265SDimitry Andric }
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoIfError(CheckerContext &C,
10481ad6265SDimitry Andric                                              const CallEvent &Call) {
10581ad6265SDimitry Andric   ProgramStateRef State = C.getState();
10681ad6265SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   ProgramStateRef StateSuccess = State->BindExpr(
10981ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
11081ad6265SDimitry Andric   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
11181ad6265SDimitry Andric 
11281ad6265SDimitry Andric   ProgramStateRef StateFailure = State->BindExpr(
11381ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
11481ad6265SDimitry Andric   StateFailure = setErrnoValue(StateFailure, C, 11, Irrelevant);
11581ad6265SDimitry Andric 
11681ad6265SDimitry Andric   C.addTransition(StateSuccess);
11781ad6265SDimitry Andric   C.addTransition(StateFailure);
11881ad6265SDimitry Andric }
11981ad6265SDimitry Andric 
12081ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,
12181ad6265SDimitry Andric                                                   const CallEvent &Call) {
12281ad6265SDimitry Andric   ProgramStateRef State = C.getState();
12381ad6265SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   ProgramStateRef StateSuccess = State->BindExpr(
12681ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
12781ad6265SDimitry Andric   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric   ProgramStateRef StateFailure = State->BindExpr(
13081ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
13181ad6265SDimitry Andric   DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(
13281ad6265SDimitry Andric       nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount());
13381ad6265SDimitry Andric   StateFailure = StateFailure->assume(ErrnoVal, true);
13481ad6265SDimitry Andric   assert(StateFailure && "Failed to assume on an initial value.");
13581ad6265SDimitry Andric   StateFailure =
13681ad6265SDimitry Andric       setErrnoValue(StateFailure, C.getLocationContext(), ErrnoVal, Irrelevant);
13781ad6265SDimitry Andric 
13881ad6265SDimitry Andric   C.addTransition(StateSuccess);
13981ad6265SDimitry Andric   C.addTransition(StateFailure);
14081ad6265SDimitry Andric }
14181ad6265SDimitry Andric 
14281ad6265SDimitry Andric void ErrnoTesterChecker::evalSetErrnoCheckState(CheckerContext &C,
14381ad6265SDimitry Andric                                                 const CallEvent &Call) {
14481ad6265SDimitry Andric   ProgramStateRef State = C.getState();
14581ad6265SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric   ProgramStateRef StateSuccess = State->BindExpr(
14881ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
14981ad6265SDimitry Andric   StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
15081ad6265SDimitry Andric 
15181ad6265SDimitry Andric   ProgramStateRef StateFailure1 = State->BindExpr(
15281ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
15381ad6265SDimitry Andric   StateFailure1 = setErrnoValue(StateFailure1, C, 1, Irrelevant);
15481ad6265SDimitry Andric 
15581ad6265SDimitry Andric   ProgramStateRef StateFailure2 = State->BindExpr(
15681ad6265SDimitry Andric       Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(2, true));
15781ad6265SDimitry Andric   StateFailure2 = setErrnoValue(StateFailure2, C, 2, MustBeChecked);
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric   C.addTransition(StateSuccess,
16081ad6265SDimitry Andric                   getErrnoNoteTag(C, "Assuming that this function succeeds but "
16181ad6265SDimitry Andric                                      "sets 'errno' to an unspecified value."));
16281ad6265SDimitry Andric   C.addTransition(StateFailure1);
16381ad6265SDimitry Andric   C.addTransition(
16481ad6265SDimitry Andric       StateFailure2,
16581ad6265SDimitry Andric       getErrnoNoteTag(C, "Assuming that this function returns 2. 'errno' "
16681ad6265SDimitry Andric                          "should be checked to test for failure."));
16781ad6265SDimitry Andric }
16881ad6265SDimitry Andric 
16981ad6265SDimitry Andric bool ErrnoTesterChecker::evalCall(const CallEvent &Call,
17081ad6265SDimitry Andric                                   CheckerContext &C) const {
17181ad6265SDimitry Andric   const EvalFn *Fn = TestCalls.lookup(Call);
17281ad6265SDimitry Andric   if (Fn) {
17381ad6265SDimitry Andric     (*Fn)(C, Call);
17481ad6265SDimitry Andric     return C.isDifferent();
17581ad6265SDimitry Andric   }
17681ad6265SDimitry Andric   return false;
17781ad6265SDimitry Andric }
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric void ento::registerErrnoTesterChecker(CheckerManager &Mgr) {
18081ad6265SDimitry Andric   Mgr.registerChecker<ErrnoTesterChecker>();
18181ad6265SDimitry Andric }
18281ad6265SDimitry Andric 
18381ad6265SDimitry Andric bool ento::shouldRegisterErrnoTesterChecker(const CheckerManager &Mgr) {
18481ad6265SDimitry Andric   return true;
18581ad6265SDimitry Andric }
186