xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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