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