ErrnoTesterChecker.cpp 8.0 KB

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