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