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