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