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.
REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion,const MemRegion *)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.
getErrnoFunc(ASTContext & ACtx)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
checkASTDecl(const TranslationUnitDecl * D,AnalysisManager & Mgr,BugReporter & BR) const118 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
checkBeginFunction(CheckerContext & C) const131 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
evalCall(const CallEvent & Call,CheckerContext & C) const181 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
checkLiveSymbols(ProgramStateRef State,SymbolReaper & SR) const200 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
getErrnoValue(ProgramStateRef State)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
setErrnoValue(ProgramStateRef State,const LocationContext * LCtx,SVal Value,ErrnoCheckState EState)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
setErrnoValue(ProgramStateRef State,CheckerContext & C,uint64_t Value,ErrnoCheckState EState)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
getErrnoLoc(ProgramStateRef State)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
getErrnoState(ProgramStateRef State)250 ErrnoCheckState getErrnoState(ProgramStateRef State) {
251 return State->get<ErrnoState>();
252 }
253
setErrnoState(ProgramStateRef State,ErrnoCheckState EState)254 ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
255 return State->set<ErrnoState>(EState);
256 }
257
clearErrnoState(ProgramStateRef State)258 ProgramStateRef clearErrnoState(ProgramStateRef State) {
259 return setErrnoState(State, Irrelevant);
260 }
261
isErrno(const Decl * D)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
describeErrnoCheckState(ErrnoCheckState CS)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
getErrnoNoteTag(CheckerContext & C,const std::string & Message)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
setErrnoForStdSuccess(ProgramStateRef State,CheckerContext & C)289 ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
290 CheckerContext &C) {
291 return setErrnoState(State, MustNotBeChecked);
292 }
293
setErrnoForStdFailure(ProgramStateRef State,CheckerContext & C,NonLoc ErrnoSym)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
setErrnoStdMustBeChecked(ProgramStateRef State,CheckerContext & C,const Expr * InvalE)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
getNoteTagForStdSuccess(CheckerContext & C,llvm::StringRef Fn)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
getNoteTagForStdMustBeChecked(CheckerContext & C,llvm::StringRef Fn)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
registerErrnoModeling(CheckerManager & mgr)340 void ento::registerErrnoModeling(CheckerManager &mgr) {
341 mgr.registerChecker<ErrnoModeling>();
342 }
343
shouldRegisterErrnoModeling(const CheckerManager & mgr)344 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
345 return true;
346 }
347