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