Coverage Report

Created: 2023-09-30 09:22

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