ErrnoChecker.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. //=== ErrnoChecker.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 an "errno checker" that can detect some invalid use of the
  10. // system-defined value 'errno'. This checker works together with the
  11. // ErrnoModeling checker and other checkers like StdCLibraryFunctions.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ErrnoModeling.h"
  15. #include "clang/AST/ParentMapContext.h"
  16. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  17. #include "clang/StaticAnalyzer/Core/Checker.h"
  18. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  23. #include "llvm/ADT/STLExtras.h"
  24. #include <optional>
  25. using namespace clang;
  26. using namespace ento;
  27. using namespace errno_modeling;
  28. namespace {
  29. class ErrnoChecker
  30. : public Checker<check::Location, check::PreCall, check::RegionChanges> {
  31. public:
  32. void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
  33. CheckerContext &) const;
  34. void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
  35. ProgramStateRef
  36. checkRegionChanges(ProgramStateRef State,
  37. const InvalidatedSymbols *Invalidated,
  38. ArrayRef<const MemRegion *> ExplicitRegions,
  39. ArrayRef<const MemRegion *> Regions,
  40. const LocationContext *LCtx, const CallEvent *Call) const;
  41. void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const;
  42. /// Indicates if a read (load) of \c errno is allowed in a non-condition part
  43. /// of \c if, \c switch, loop and conditional statements when the errno
  44. /// value may be undefined.
  45. bool AllowErrnoReadOutsideConditions = true;
  46. private:
  47. void generateErrnoNotCheckedBug(CheckerContext &C, ProgramStateRef State,
  48. const MemRegion *ErrnoRegion,
  49. const CallEvent *CallMayChangeErrno) const;
  50. BugType BT_InvalidErrnoRead{this, "Value of 'errno' could be undefined",
  51. "Error handling"};
  52. BugType BT_ErrnoNotChecked{this, "Value of 'errno' was not checked",
  53. "Error handling"};
  54. };
  55. } // namespace
  56. static ProgramStateRef setErrnoStateIrrelevant(ProgramStateRef State) {
  57. return setErrnoState(State, Irrelevant);
  58. }
  59. /// Check if a statement (expression) or an ancestor of it is in a condition
  60. /// part of a (conditional, loop, switch) statement.
  61. static bool isInCondition(const Stmt *S, CheckerContext &C) {
  62. ParentMapContext &ParentCtx = C.getASTContext().getParentMapContext();
  63. bool CondFound = false;
  64. while (S && !CondFound) {
  65. const DynTypedNodeList Parents = ParentCtx.getParents(*S);
  66. if (Parents.empty())
  67. break;
  68. const auto *ParentS = Parents[0].get<Stmt>();
  69. if (!ParentS || isa<CallExpr>(ParentS))
  70. break;
  71. switch (ParentS->getStmtClass()) {
  72. case Expr::IfStmtClass:
  73. CondFound = (S == cast<IfStmt>(ParentS)->getCond());
  74. break;
  75. case Expr::ForStmtClass:
  76. CondFound = (S == cast<ForStmt>(ParentS)->getCond());
  77. break;
  78. case Expr::DoStmtClass:
  79. CondFound = (S == cast<DoStmt>(ParentS)->getCond());
  80. break;
  81. case Expr::WhileStmtClass:
  82. CondFound = (S == cast<WhileStmt>(ParentS)->getCond());
  83. break;
  84. case Expr::SwitchStmtClass:
  85. CondFound = (S == cast<SwitchStmt>(ParentS)->getCond());
  86. break;
  87. case Expr::ConditionalOperatorClass:
  88. CondFound = (S == cast<ConditionalOperator>(ParentS)->getCond());
  89. break;
  90. case Expr::BinaryConditionalOperatorClass:
  91. CondFound = (S == cast<BinaryConditionalOperator>(ParentS)->getCommon());
  92. break;
  93. default:
  94. break;
  95. }
  96. S = ParentS;
  97. }
  98. return CondFound;
  99. }
  100. void ErrnoChecker::generateErrnoNotCheckedBug(
  101. CheckerContext &C, ProgramStateRef State, const MemRegion *ErrnoRegion,
  102. const CallEvent *CallMayChangeErrno) const {
  103. if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
  104. SmallString<100> StrBuf;
  105. llvm::raw_svector_ostream OS(StrBuf);
  106. if (CallMayChangeErrno) {
  107. OS << "Value of 'errno' was not checked and may be overwritten by "
  108. "function '";
  109. const auto *CallD =
  110. dyn_cast_or_null<FunctionDecl>(CallMayChangeErrno->getDecl());
  111. assert(CallD && CallD->getIdentifier());
  112. OS << CallD->getIdentifier()->getName() << "'";
  113. } else {
  114. OS << "Value of 'errno' was not checked and is overwritten here";
  115. }
  116. auto BR = std::make_unique<PathSensitiveBugReport>(BT_ErrnoNotChecked,
  117. OS.str(), N);
  118. BR->markInteresting(ErrnoRegion);
  119. C.emitReport(std::move(BR));
  120. }
  121. }
  122. void ErrnoChecker::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
  123. CheckerContext &C) const {
  124. std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
  125. if (!ErrnoLoc)
  126. return;
  127. auto L = Loc.getAs<ento::Loc>();
  128. if (!L || *ErrnoLoc != *L)
  129. return;
  130. ProgramStateRef State = C.getState();
  131. ErrnoCheckState EState = getErrnoState(State);
  132. if (IsLoad) {
  133. switch (EState) {
  134. case MustNotBeChecked:
  135. // Read of 'errno' when it may have undefined value.
  136. if (!AllowErrnoReadOutsideConditions || isInCondition(S, C)) {
  137. if (ExplodedNode *N = C.generateErrorNode()) {
  138. auto BR = std::make_unique<PathSensitiveBugReport>(
  139. BT_InvalidErrnoRead,
  140. "An undefined value may be read from 'errno'", N);
  141. BR->markInteresting(ErrnoLoc->getAsRegion());
  142. C.emitReport(std::move(BR));
  143. }
  144. }
  145. break;
  146. case MustBeChecked:
  147. // 'errno' has to be checked. A load is required for this, with no more
  148. // information we can assume that it is checked somehow.
  149. // After this place 'errno' is allowed to be read and written.
  150. State = setErrnoStateIrrelevant(State);
  151. C.addTransition(State);
  152. break;
  153. default:
  154. break;
  155. }
  156. } else {
  157. switch (EState) {
  158. case MustBeChecked:
  159. // 'errno' is overwritten without a read before but it should have been
  160. // checked.
  161. generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(State),
  162. ErrnoLoc->getAsRegion(), nullptr);
  163. break;
  164. case MustNotBeChecked:
  165. // Write to 'errno' when it is not allowed to be read.
  166. // After this place 'errno' is allowed to be read and written.
  167. State = setErrnoStateIrrelevant(State);
  168. C.addTransition(State);
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. }
  175. void ErrnoChecker::checkPreCall(const CallEvent &Call,
  176. CheckerContext &C) const {
  177. const auto *CallF = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  178. if (!CallF)
  179. return;
  180. CallF = CallF->getCanonicalDecl();
  181. // If 'errno' must be checked, it should be done as soon as possible, and
  182. // before any other call to a system function (something in a system header).
  183. // To avoid use of a long list of functions that may change 'errno'
  184. // (which may be different with standard library versions) assume that any
  185. // function can change it.
  186. // A list of special functions can be used that are allowed here without
  187. // generation of diagnostic. For now the only such case is 'errno' itself.
  188. // Probably 'strerror'?
  189. if (CallF->isExternC() && CallF->isGlobal() &&
  190. C.getSourceManager().isInSystemHeader(CallF->getLocation()) &&
  191. !isErrno(CallF)) {
  192. if (getErrnoState(C.getState()) == MustBeChecked) {
  193. std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
  194. assert(ErrnoLoc && "ErrnoLoc should exist if an errno state is set.");
  195. generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(C.getState()),
  196. ErrnoLoc->getAsRegion(), &Call);
  197. }
  198. }
  199. }
  200. ProgramStateRef ErrnoChecker::checkRegionChanges(
  201. ProgramStateRef State, const InvalidatedSymbols *Invalidated,
  202. ArrayRef<const MemRegion *> ExplicitRegions,
  203. ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
  204. const CallEvent *Call) const {
  205. std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
  206. if (!ErrnoLoc)
  207. return State;
  208. const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion();
  209. // If 'errno' is invalidated we can not know if it is checked or written into,
  210. // allow read and write without bug reports.
  211. if (llvm::is_contained(Regions, ErrnoRegion))
  212. return clearErrnoState(State);
  213. // Always reset errno state when the system memory space is invalidated.
  214. // The ErrnoRegion is not always found in the list in this case.
  215. if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace()))
  216. return clearErrnoState(State);
  217. return State;
  218. }
  219. void ento::registerErrnoChecker(CheckerManager &mgr) {
  220. const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
  221. auto *Checker = mgr.registerChecker<ErrnoChecker>();
  222. Checker->AllowErrnoReadOutsideConditions = Opts.getCheckerBooleanOption(
  223. Checker, "AllowErrnoReadOutsideConditionExpressions");
  224. }
  225. bool ento::shouldRegisterErrnoChecker(const CheckerManager &mgr) {
  226. return true;
  227. }