1*12c85518Srobert //=== ErrnoModeling.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 a checker `ErrnoModeling`, which is used to make the system
10*12c85518Srobert // value 'errno' available to other checkers.
11*12c85518Srobert // The 'errno' value is stored at a special memory region that is accessible
12*12c85518Srobert // through the `errno_modeling` namespace. The memory region is either the
13*12c85518Srobert // region of `errno` itself if it is a variable, otherwise an artifically
14*12c85518Srobert // created region (in the system memory space). If `errno` is defined by using
15*12c85518Srobert // a function which returns the address of it (this is always the case if it is
16*12c85518Srobert // not a variable) this function is recognized and evaluated. In this way
17*12c85518Srobert // `errno` becomes visible to the analysis and checkers can change its value.
18*12c85518Srobert //
19*12c85518Srobert //===----------------------------------------------------------------------===//
20*12c85518Srobert
21*12c85518Srobert #include "ErrnoModeling.h"
22*12c85518Srobert #include "clang/AST/ParentMapContext.h"
23*12c85518Srobert #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
24*12c85518Srobert #include "clang/StaticAnalyzer/Core/Checker.h"
25*12c85518Srobert #include "clang/StaticAnalyzer/Core/CheckerManager.h"
26*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
27*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
28*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
29*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
30*12c85518Srobert #include "llvm/ADT/STLExtras.h"
31*12c85518Srobert #include <optional>
32*12c85518Srobert
33*12c85518Srobert using namespace clang;
34*12c85518Srobert using namespace ento;
35*12c85518Srobert
36*12c85518Srobert namespace {
37*12c85518Srobert
38*12c85518Srobert // Name of the "errno" variable.
39*12c85518Srobert // FIXME: Is there a system where it is not called "errno" but is a variable?
40*12c85518Srobert const char *ErrnoVarName = "errno";
41*12c85518Srobert // Names of functions that return a location of the "errno" value.
42*12c85518Srobert // FIXME: Are there other similar function names?
43*12c85518Srobert const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno",
44*12c85518Srobert "__errno", "_errno", "__error"};
45*12c85518Srobert
46*12c85518Srobert class ErrnoModeling
47*12c85518Srobert : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
48*12c85518Srobert check::LiveSymbols, eval::Call> {
49*12c85518Srobert public:
50*12c85518Srobert void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
51*12c85518Srobert BugReporter &BR) const;
52*12c85518Srobert void checkBeginFunction(CheckerContext &C) const;
53*12c85518Srobert void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
54*12c85518Srobert bool evalCall(const CallEvent &Call, CheckerContext &C) const;
55*12c85518Srobert
56*12c85518Srobert // The declaration of an "errno" variable or "errno location" function.
57*12c85518Srobert mutable const Decl *ErrnoDecl = nullptr;
58*12c85518Srobert
59*12c85518Srobert private:
60*12c85518Srobert // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
61*12c85518Srobert CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
62*12c85518Srobert {{"___errno"}, 0, 0},
63*12c85518Srobert {{"__errno"}, 0, 0},
64*12c85518Srobert {{"_errno"}, 0, 0},
65*12c85518Srobert {{"__error"}, 0, 0}};
66*12c85518Srobert };
67*12c85518Srobert
68*12c85518Srobert } // namespace
69*12c85518Srobert
70*12c85518Srobert /// Store a MemRegion that contains the 'errno' integer value.
71*12c85518Srobert /// The value is null if the 'errno' value was not recognized in the AST.
REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion,const MemRegion *)72*12c85518Srobert REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
73*12c85518Srobert
74*12c85518Srobert REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState)
75*12c85518Srobert
76*12c85518Srobert /// Search for a variable called "errno" in the AST.
77*12c85518Srobert /// Return nullptr if not found.
78*12c85518Srobert static const VarDecl *getErrnoVar(ASTContext &ACtx) {
79*12c85518Srobert IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
80*12c85518Srobert auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
81*12c85518Srobert auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
82*12c85518Srobert if (auto *VD = dyn_cast<VarDecl>(D))
83*12c85518Srobert return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
84*12c85518Srobert VD->hasExternalStorage() &&
85*12c85518Srobert VD->getType().getCanonicalType() == ACtx.IntTy;
86*12c85518Srobert return false;
87*12c85518Srobert });
88*12c85518Srobert if (Found == LookupRes.end())
89*12c85518Srobert return nullptr;
90*12c85518Srobert
91*12c85518Srobert return cast<VarDecl>(*Found);
92*12c85518Srobert }
93*12c85518Srobert
94*12c85518Srobert /// Search for a function with a specific name that is used to return a pointer
95*12c85518Srobert /// to "errno".
96*12c85518Srobert /// Return nullptr if no such function was found.
getErrnoFunc(ASTContext & ACtx)97*12c85518Srobert static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) {
98*12c85518Srobert SmallVector<const Decl *> LookupRes;
99*12c85518Srobert for (StringRef ErrnoName : ErrnoLocationFuncNames) {
100*12c85518Srobert IdentifierInfo &II = ACtx.Idents.get(ErrnoName);
101*12c85518Srobert llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II));
102*12c85518Srobert }
103*12c85518Srobert
104*12c85518Srobert auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
105*12c85518Srobert if (auto *FD = dyn_cast<FunctionDecl>(D))
106*12c85518Srobert return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) &&
107*12c85518Srobert FD->isExternC() && FD->getNumParams() == 0 &&
108*12c85518Srobert FD->getReturnType().getCanonicalType() ==
109*12c85518Srobert ACtx.getPointerType(ACtx.IntTy);
110*12c85518Srobert return false;
111*12c85518Srobert });
112*12c85518Srobert if (Found == LookupRes.end())
113*12c85518Srobert return nullptr;
114*12c85518Srobert
115*12c85518Srobert return cast<FunctionDecl>(*Found);
116*12c85518Srobert }
117*12c85518Srobert
checkASTDecl(const TranslationUnitDecl * D,AnalysisManager & Mgr,BugReporter & BR) const118*12c85518Srobert void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
119*12c85518Srobert AnalysisManager &Mgr, BugReporter &BR) const {
120*12c85518Srobert // Try to find an usable `errno` value.
121*12c85518Srobert // It can be an external variable called "errno" or a function that returns a
122*12c85518Srobert // pointer to the "errno" value. This function can have different names.
123*12c85518Srobert // The actual case is dependent on the C library implementation, we
124*12c85518Srobert // can only search for a match in one of these variations.
125*12c85518Srobert // We assume that exactly one of these cases might be true.
126*12c85518Srobert ErrnoDecl = getErrnoVar(Mgr.getASTContext());
127*12c85518Srobert if (!ErrnoDecl)
128*12c85518Srobert ErrnoDecl = getErrnoFunc(Mgr.getASTContext());
129*12c85518Srobert }
130*12c85518Srobert
checkBeginFunction(CheckerContext & C) const131*12c85518Srobert void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
132*12c85518Srobert if (!C.inTopFrame())
133*12c85518Srobert return;
134*12c85518Srobert
135*12c85518Srobert ASTContext &ACtx = C.getASTContext();
136*12c85518Srobert ProgramStateRef State = C.getState();
137*12c85518Srobert
138*12c85518Srobert if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
139*12c85518Srobert // There is an external 'errno' variable.
140*12c85518Srobert // Use its memory region.
141*12c85518Srobert // The memory region for an 'errno'-like variable is allocated in system
142*12c85518Srobert // space by MemRegionManager.
143*12c85518Srobert const MemRegion *ErrnoR =
144*12c85518Srobert State->getRegion(ErrnoVar, C.getLocationContext());
145*12c85518Srobert assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
146*12c85518Srobert State = State->set<ErrnoRegion>(ErrnoR);
147*12c85518Srobert State =
148*12c85518Srobert errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
149*12c85518Srobert C.addTransition(State);
150*12c85518Srobert } else if (ErrnoDecl) {
151*12c85518Srobert assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function.");
152*12c85518Srobert // There is a function that returns the location of 'errno'.
153*12c85518Srobert // We must create a memory region for it in system space.
154*12c85518Srobert // Currently a symbolic region is used with an artifical symbol.
155*12c85518Srobert // FIXME: It is better to have a custom (new) kind of MemRegion for such
156*12c85518Srobert // cases.
157*12c85518Srobert SValBuilder &SVB = C.getSValBuilder();
158*12c85518Srobert MemRegionManager &RMgr = C.getStateManager().getRegionManager();
159*12c85518Srobert
160*12c85518Srobert const MemSpaceRegion *GlobalSystemSpace =
161*12c85518Srobert RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
162*12c85518Srobert
163*12c85518Srobert // Create an artifical symbol for the region.
164*12c85518Srobert // It is not possible to associate a statement or expression in this case.
165*12c85518Srobert const SymbolConjured *Sym = SVB.conjureSymbol(
166*12c85518Srobert nullptr, C.getLocationContext(),
167*12c85518Srobert ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
168*12c85518Srobert
169*12c85518Srobert // The symbolic region is untyped, create a typed sub-region in it.
170*12c85518Srobert // The ElementRegion is used to make the errno region a typed region.
171*12c85518Srobert const MemRegion *ErrnoR = RMgr.getElementRegion(
172*12c85518Srobert ACtx.IntTy, SVB.makeZeroArrayIndex(),
173*12c85518Srobert RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
174*12c85518Srobert State = State->set<ErrnoRegion>(ErrnoR);
175*12c85518Srobert State =
176*12c85518Srobert errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant);
177*12c85518Srobert C.addTransition(State);
178*12c85518Srobert }
179*12c85518Srobert }
180*12c85518Srobert
evalCall(const CallEvent & Call,CheckerContext & C) const181*12c85518Srobert bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
182*12c85518Srobert // Return location of "errno" at a call to an "errno address returning"
183*12c85518Srobert // function.
184*12c85518Srobert if (ErrnoLocationCalls.contains(Call)) {
185*12c85518Srobert ProgramStateRef State = C.getState();
186*12c85518Srobert
187*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
188*12c85518Srobert if (!ErrnoR)
189*12c85518Srobert return false;
190*12c85518Srobert
191*12c85518Srobert State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
192*12c85518Srobert loc::MemRegionVal{ErrnoR});
193*12c85518Srobert C.addTransition(State);
194*12c85518Srobert return true;
195*12c85518Srobert }
196*12c85518Srobert
197*12c85518Srobert return false;
198*12c85518Srobert }
199*12c85518Srobert
checkLiveSymbols(ProgramStateRef State,SymbolReaper & SR) const200*12c85518Srobert void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
201*12c85518Srobert SymbolReaper &SR) const {
202*12c85518Srobert // The special errno region should never garbage collected.
203*12c85518Srobert if (const auto *ErrnoR = State->get<ErrnoRegion>())
204*12c85518Srobert SR.markLive(ErrnoR);
205*12c85518Srobert }
206*12c85518Srobert
207*12c85518Srobert namespace clang {
208*12c85518Srobert namespace ento {
209*12c85518Srobert namespace errno_modeling {
210*12c85518Srobert
getErrnoValue(ProgramStateRef State)211*12c85518Srobert std::optional<SVal> getErrnoValue(ProgramStateRef State) {
212*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
213*12c85518Srobert if (!ErrnoR)
214*12c85518Srobert return {};
215*12c85518Srobert QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
216*12c85518Srobert return State->getSVal(ErrnoR, IntTy);
217*12c85518Srobert }
218*12c85518Srobert
setErrnoValue(ProgramStateRef State,const LocationContext * LCtx,SVal Value,ErrnoCheckState EState)219*12c85518Srobert ProgramStateRef setErrnoValue(ProgramStateRef State,
220*12c85518Srobert const LocationContext *LCtx, SVal Value,
221*12c85518Srobert ErrnoCheckState EState) {
222*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
223*12c85518Srobert if (!ErrnoR)
224*12c85518Srobert return State;
225*12c85518Srobert // First set the errno value, the old state is still available at 'checkBind'
226*12c85518Srobert // or 'checkLocation' for errno value.
227*12c85518Srobert State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
228*12c85518Srobert return State->set<ErrnoState>(EState);
229*12c85518Srobert }
230*12c85518Srobert
setErrnoValue(ProgramStateRef State,CheckerContext & C,uint64_t Value,ErrnoCheckState EState)231*12c85518Srobert ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
232*12c85518Srobert uint64_t Value, ErrnoCheckState EState) {
233*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
234*12c85518Srobert if (!ErrnoR)
235*12c85518Srobert return State;
236*12c85518Srobert State = State->bindLoc(
237*12c85518Srobert loc::MemRegionVal{ErrnoR},
238*12c85518Srobert C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
239*12c85518Srobert C.getLocationContext());
240*12c85518Srobert return State->set<ErrnoState>(EState);
241*12c85518Srobert }
242*12c85518Srobert
getErrnoLoc(ProgramStateRef State)243*12c85518Srobert std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
244*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
245*12c85518Srobert if (!ErrnoR)
246*12c85518Srobert return {};
247*12c85518Srobert return loc::MemRegionVal{ErrnoR};
248*12c85518Srobert }
249*12c85518Srobert
getErrnoState(ProgramStateRef State)250*12c85518Srobert ErrnoCheckState getErrnoState(ProgramStateRef State) {
251*12c85518Srobert return State->get<ErrnoState>();
252*12c85518Srobert }
253*12c85518Srobert
setErrnoState(ProgramStateRef State,ErrnoCheckState EState)254*12c85518Srobert ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
255*12c85518Srobert return State->set<ErrnoState>(EState);
256*12c85518Srobert }
257*12c85518Srobert
clearErrnoState(ProgramStateRef State)258*12c85518Srobert ProgramStateRef clearErrnoState(ProgramStateRef State) {
259*12c85518Srobert return setErrnoState(State, Irrelevant);
260*12c85518Srobert }
261*12c85518Srobert
isErrno(const Decl * D)262*12c85518Srobert bool isErrno(const Decl *D) {
263*12c85518Srobert if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
264*12c85518Srobert if (const IdentifierInfo *II = VD->getIdentifier())
265*12c85518Srobert return II->getName() == ErrnoVarName;
266*12c85518Srobert if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
267*12c85518Srobert if (const IdentifierInfo *II = FD->getIdentifier())
268*12c85518Srobert return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
269*12c85518Srobert return false;
270*12c85518Srobert }
271*12c85518Srobert
describeErrnoCheckState(ErrnoCheckState CS)272*12c85518Srobert const char *describeErrnoCheckState(ErrnoCheckState CS) {
273*12c85518Srobert assert(CS == errno_modeling::MustNotBeChecked &&
274*12c85518Srobert "Errno description not applicable.");
275*12c85518Srobert return "may be undefined after the call and should not be used";
276*12c85518Srobert }
277*12c85518Srobert
getErrnoNoteTag(CheckerContext & C,const std::string & Message)278*12c85518Srobert const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
279*12c85518Srobert return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
280*12c85518Srobert const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
281*12c85518Srobert if (ErrnoR && BR.isInteresting(ErrnoR)) {
282*12c85518Srobert BR.markNotInteresting(ErrnoR);
283*12c85518Srobert return Message;
284*12c85518Srobert }
285*12c85518Srobert return "";
286*12c85518Srobert });
287*12c85518Srobert }
288*12c85518Srobert
setErrnoForStdSuccess(ProgramStateRef State,CheckerContext & C)289*12c85518Srobert ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
290*12c85518Srobert CheckerContext &C) {
291*12c85518Srobert return setErrnoState(State, MustNotBeChecked);
292*12c85518Srobert }
293*12c85518Srobert
setErrnoForStdFailure(ProgramStateRef State,CheckerContext & C,NonLoc ErrnoSym)294*12c85518Srobert ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
295*12c85518Srobert NonLoc ErrnoSym) {
296*12c85518Srobert SValBuilder &SVB = C.getSValBuilder();
297*12c85518Srobert NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
298*12c85518Srobert DefinedOrUnknownSVal Cond =
299*12c85518Srobert SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
300*12c85518Srobert .castAs<DefinedOrUnknownSVal>();
301*12c85518Srobert State = State->assume(Cond, true);
302*12c85518Srobert if (!State)
303*12c85518Srobert return nullptr;
304*12c85518Srobert return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
305*12c85518Srobert }
306*12c85518Srobert
setErrnoStdMustBeChecked(ProgramStateRef State,CheckerContext & C,const Expr * InvalE)307*12c85518Srobert ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
308*12c85518Srobert CheckerContext &C,
309*12c85518Srobert const Expr *InvalE) {
310*12c85518Srobert const MemRegion *ErrnoR = State->get<ErrnoRegion>();
311*12c85518Srobert if (!ErrnoR)
312*12c85518Srobert return State;
313*12c85518Srobert State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
314*12c85518Srobert C.getLocationContext(), false);
315*12c85518Srobert if (!State)
316*12c85518Srobert return nullptr;
317*12c85518Srobert return setErrnoState(State, MustBeChecked);
318*12c85518Srobert }
319*12c85518Srobert
getNoteTagForStdSuccess(CheckerContext & C,llvm::StringRef Fn)320*12c85518Srobert const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
321*12c85518Srobert return getErrnoNoteTag(
322*12c85518Srobert C, (Twine("Assuming that function '") + Twine(Fn) +
323*12c85518Srobert Twine("' is successful, in this case the value 'errno' ") +
324*12c85518Srobert Twine(describeErrnoCheckState(MustNotBeChecked)))
325*12c85518Srobert .str());
326*12c85518Srobert }
327*12c85518Srobert
getNoteTagForStdMustBeChecked(CheckerContext & C,llvm::StringRef Fn)328*12c85518Srobert const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
329*12c85518Srobert llvm::StringRef Fn) {
330*12c85518Srobert return getErrnoNoteTag(
331*12c85518Srobert C, (Twine("Function '") + Twine(Fn) +
332*12c85518Srobert Twine("' indicates failure only by setting of 'errno'"))
333*12c85518Srobert .str());
334*12c85518Srobert }
335*12c85518Srobert
336*12c85518Srobert } // namespace errno_modeling
337*12c85518Srobert } // namespace ento
338*12c85518Srobert } // namespace clang
339*12c85518Srobert
registerErrnoModeling(CheckerManager & mgr)340*12c85518Srobert void ento::registerErrnoModeling(CheckerManager &mgr) {
341*12c85518Srobert mgr.registerChecker<ErrnoModeling>();
342*12c85518Srobert }
343*12c85518Srobert
shouldRegisterErrnoModeling(const CheckerManager & mgr)344*12c85518Srobert bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
345*12c85518Srobert return true;
346*12c85518Srobert }
347