clang  19.0.0git
ErrnoModeling.cpp
Go to the documentation of this file.
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"
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 
43 // Names of functions that return a location of the "errno" value.
44 // FIXME: Are there other similar function names?
45 CallDescriptionSet ErrnoLocationCalls{
46  {CDM::CLibrary, {"__errno_location"}, 0, 0},
47  {CDM::CLibrary, {"___errno"}, 0, 0},
48  {CDM::CLibrary, {"__errno"}, 0, 0},
49  {CDM::CLibrary, {"_errno"}, 0, 0},
50  {CDM::CLibrary, {"__error"}, 0, 0}};
51 
52 class ErrnoModeling
53  : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
54  check::LiveSymbols, eval::Call> {
55 public:
56  void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
57  BugReporter &BR) const;
58  void checkBeginFunction(CheckerContext &C) const;
59  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
60  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
61 
62 private:
63  // The declaration of an "errno" variable on systems where errno is
64  // represented by a variable (and not a function that queries its location).
65  mutable const VarDecl *ErrnoDecl = nullptr;
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 
75 
76 void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
77  AnalysisManager &Mgr, BugReporter &BR) const {
78  // Try to find the declaration of the external variable `int errno;`.
79  // There are also C library implementations, where the `errno` location is
80  // accessed via a function that returns its address; in those environments
81  // this callback has no effect.
82  ASTContext &ACtx = Mgr.getASTContext();
83  IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
84  auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
85  auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
86  if (auto *VD = dyn_cast<VarDecl>(D))
87  return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
88  VD->hasExternalStorage() &&
89  VD->getType().getCanonicalType() == ACtx.IntTy;
90  return false;
91  });
92  if (Found != LookupRes.end())
93  ErrnoDecl = cast<VarDecl>(*Found);
94 }
95 
96 void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
97  if (!C.inTopFrame())
98  return;
99 
100  ASTContext &ACtx = C.getASTContext();
101  ProgramStateRef State = C.getState();
102 
103  const MemRegion *ErrnoR = nullptr;
104 
105  if (ErrnoDecl) {
106  // There is an external 'errno' variable, so we can simply use the memory
107  // region that's associated with it.
108  ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext());
109  assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
110  } else {
111  // There is no 'errno' variable, so create a new symbolic memory region
112  // that can be used to model the return value of the "get the location of
113  // errno" internal functions.
114  // NOTE: this `SVal` is created even if errno is not defined or used.
115  SValBuilder &SVB = C.getSValBuilder();
116  MemRegionManager &RMgr = C.getStateManager().getRegionManager();
117 
118  const MemSpaceRegion *GlobalSystemSpace =
119  RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
120 
121  // Create an artifical symbol for the region.
122  // Note that it is not possible to associate a statement or expression in
123  // this case and the `symbolTag` (opaque pointer tag) is just the address
124  // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
125  // object.
126  const SymbolConjured *Sym = SVB.conjureSymbol(
127  nullptr, C.getLocationContext(),
128  ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
129 
130  // The symbolic region is untyped, create a typed sub-region in it.
131  // The ElementRegion is used to make the errno region a typed region.
132  ErrnoR = RMgr.getElementRegion(
133  ACtx.IntTy, SVB.makeZeroArrayIndex(),
134  RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
135  }
136  assert(ErrnoR);
137  State = State->set<ErrnoRegion>(ErrnoR);
138  State =
140  C.addTransition(State);
141 }
142 
143 bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
144  // Return location of "errno" at a call to an "errno address returning"
145  // function.
147  ProgramStateRef State = C.getState();
148 
149  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
150  if (!ErrnoR)
151  return false;
152 
153  State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
154  loc::MemRegionVal{ErrnoR});
155  C.addTransition(State);
156  return true;
157  }
158 
159  return false;
160 }
161 
162 void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
163  SymbolReaper &SR) const {
164  // The special errno region should never garbage collected.
165  if (const auto *ErrnoR = State->get<ErrnoRegion>())
166  SR.markLive(ErrnoR);
167 }
168 
169 namespace clang {
170 namespace ento {
171 namespace errno_modeling {
172 
173 std::optional<SVal> getErrnoValue(ProgramStateRef State) {
174  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
175  if (!ErrnoR)
176  return {};
177  QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
178  return State->getSVal(ErrnoR, IntTy);
179 }
180 
182  const LocationContext *LCtx, SVal Value,
183  ErrnoCheckState EState) {
184  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
185  if (!ErrnoR)
186  return State;
187  // First set the errno value, the old state is still available at 'checkBind'
188  // or 'checkLocation' for errno value.
189  State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
190  return State->set<ErrnoState>(EState);
191 }
192 
194  uint64_t Value, ErrnoCheckState EState) {
195  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
196  if (!ErrnoR)
197  return State;
198  State = State->bindLoc(
199  loc::MemRegionVal{ErrnoR},
200  C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
201  C.getLocationContext());
202  return State->set<ErrnoState>(EState);
203 }
204 
205 std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
206  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
207  if (!ErrnoR)
208  return {};
209  return loc::MemRegionVal{ErrnoR};
210 }
211 
213  return State->get<ErrnoState>();
214 }
215 
217  return State->set<ErrnoState>(EState);
218 }
219 
221  return setErrnoState(State, Irrelevant);
222 }
223 
225  return ErrnoLocationCalls.contains(CE);
226 }
227 
228 const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
229  return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
230  const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
231  if (ErrnoR && BR.isInteresting(ErrnoR)) {
232  BR.markNotInteresting(ErrnoR);
233  return Message;
234  }
235  return "";
236  });
237 }
238 
240  CheckerContext &C) {
242 }
243 
245  NonLoc ErrnoSym) {
246  SValBuilder &SVB = C.getSValBuilder();
247  NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
248  DefinedOrUnknownSVal Cond =
249  SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
250  .castAs<DefinedOrUnknownSVal>();
251  State = State->assume(Cond, true);
252  if (!State)
253  return nullptr;
254  return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
255 }
256 
258  CheckerContext &C,
259  const Expr *InvalE) {
260  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
261  if (!ErrnoR)
262  return State;
263  State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
264  C.getLocationContext(), false);
265  if (!State)
266  return nullptr;
268 }
269 
270 } // namespace errno_modeling
271 } // namespace ento
272 } // namespace clang
273 
274 void ento::registerErrnoModeling(CheckerManager &mgr) {
275  mgr.registerChecker<ErrnoModeling>();
276 }
277 
278 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
279  return true;
280 }
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
LineState State
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
SourceManager & getSourceManager()
Definition: ASTContext.h:708
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
IdentifierTable & Idents
Definition: ASTContext.h:647
CanQualType IntTy
Definition: ASTContext.h:1103
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1076
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1802
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
A (possibly-)qualified type.
Definition: Type.h:940
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
The top declaration context.
Definition: Decl.h:84
Represents a variable declaration or definition.
Definition: Decl.h:919
ASTContext & getASTContext() override
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:585
An immutable set of CallDescriptions.
@ CLibrary
Match calls to functions from the C standard library.
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:153
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const ElementRegion * getElementRegion(QualType elementType, NonLoc Idx, const SubRegion *superRegion, ASTContext &Ctx)
getElementRegion - Retrieve the memory region associated with the associated element type,...
Definition: MemRegion.cpp:1159
const GlobalsSpaceRegion * getGlobalsRegion(MemRegion::Kind K=MemRegion::GlobalInternalSpaceRegionKind, const CodeTextRegion *R=nullptr)
getGlobalsRegion - Retrieve the memory region associated with global variables.
Definition: MemRegion.cpp:915
const SymbolicRegion * getSymbolicRegion(SymbolRef Sym, const MemSpaceRegion *MemSpace=nullptr)
Retrieve or create a "symbolic" memory region.
Definition: MemRegion.cpp:1192
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:96
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Definition: MemRegion.h:203
The tag upon which the TagVisitor reacts.
Definition: BugReporter.h:779
const ExplodedNode * getErrorNode() const
Definition: BugReporter.h:402
bool isInteresting(SymbolRef sym) const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
Definition: SValBuilder.cpp:62
const SymbolConjured * conjureSymbol(const Stmt *stmt, const LocationContext *LCtx, QualType type, unsigned visitCount, const void *symbolTag=nullptr)
Definition: SValBuilder.h:174
QualType getConditionType() const
Definition: SValBuilder.h:153
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:55
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:82
A symbol representing the result of an expression in the case when we do not know anything about what...
Definition: SymbolManager.h:79
A class responsible for cleaning up unused symbols.
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
std::optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
ProgramStateRef setErrnoValue(ProgramStateRef State, const LocationContext *LCtx, SVal Value, ErrnoCheckState EState)
Set value of 'errno' to any SVal, if possible.
ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, uint64_t Value, ErrnoCheckState EState)
Set value of 'errno' to a concrete (signed) integer, if possible.
ProgramStateRef clearErrnoState(ProgramStateRef State)
Clear state of errno (make it irrelevant).
ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C)
Set errno state for the common case when a standard function is successful.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
const NoteTag * getErrnoNoteTag(CheckerContext &C, const std::string &Message)
Create a NoteTag that displays the message if the 'errno' memory region is marked as interesting,...
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, const Expr *InvalE)
Set errno state for the common case when a standard function indicates failure only by errno.
bool isErrnoLocationCall(const CallEvent &CE)
Determine if Call is a call to an internal function that returns the location of errno (in environmen...
ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, NonLoc ErrnoSym)
Set errno state for the common case when a standard function fails.
std::optional< SVal > getErrnoValue(ProgramStateRef State)
Returns the value of 'errno', if 'errno' was found in the AST.
ErrnoCheckState
Describe how reads and writes of errno are handled by the checker.
Definition: ErrnoModeling.h:26
@ MustBeChecked
Value of 'errno' should be checked to find out if a previous function call has failed.
Definition: ErrnoModeling.h:36
@ Irrelevant
We do not know anything about 'errno'.
Definition: ErrnoModeling.h:29
@ MustNotBeChecked
Value of 'errno' is not allowed to be read, it can contain an unspecified value.
Definition: ErrnoModeling.h:42
ErrnoCheckState getErrnoState(ProgramStateRef State)
Returns the errno check state, Errno_Irrelevant if 'errno' was not found (this is not the only case f...
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2179
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t