clang  15.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 
32 using namespace clang;
33 using namespace ento;
34 
35 namespace {
36 
37 // Name of the "errno" variable.
38 // FIXME: Is there a system where it is not called "errno" but is a variable?
39 const char *ErrnoVarName = "errno";
40 // Names of functions that return a location of the "errno" value.
41 // FIXME: Are there other similar function names?
42 const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno",
43  "__errno", "_errno", "__error"};
44 
45 class ErrnoModeling
46  : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
47  check::LiveSymbols, eval::Call> {
48 public:
49  void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &Mgr,
50  BugReporter &BR) const;
51  void checkBeginFunction(CheckerContext &C) const;
52  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
53  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54 
55  // The declaration of an "errno" variable or "errno location" function.
56  mutable const Decl *ErrnoDecl = nullptr;
57 
58 private:
59  // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
60  CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0},
61  {"___errno", 0, 0},
62  {"__errno", 0, 0},
63  {"_errno", 0, 0},
64  {"__error", 0, 0}};
65 };
66 
67 } // namespace
68 
69 /// Store a MemRegion that contains the 'errno' integer value.
70 /// The value is null if the 'errno' value was not recognized in the AST.
71 REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *)
72 
74 
75 /// Search for a variable called "errno" in the AST.
76 /// Return nullptr if not found.
77 static const VarDecl *getErrnoVar(ASTContext &ACtx) {
78  IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName);
79  auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
80  auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
81  if (auto *VD = dyn_cast<VarDecl>(D))
82  return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
83  VD->hasExternalStorage() &&
84  VD->getType().getCanonicalType() == ACtx.IntTy;
85  return false;
86  });
87  if (Found == LookupRes.end())
88  return nullptr;
89 
90  return cast<VarDecl>(*Found);
91 }
92 
93 /// Search for a function with a specific name that is used to return a pointer
94 /// to "errno".
95 /// Return nullptr if no such function was found.
96 static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) {
97  SmallVector<const Decl *> LookupRes;
98  for (StringRef ErrnoName : ErrnoLocationFuncNames) {
99  IdentifierInfo &II = ACtx.Idents.get(ErrnoName);
100  llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II));
101  }
102 
103  auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) {
104  if (auto *FD = dyn_cast<FunctionDecl>(D))
105  return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) &&
106  FD->isExternC() && FD->getNumParams() == 0 &&
107  FD->getReturnType().getCanonicalType() ==
108  ACtx.getPointerType(ACtx.IntTy);
109  return false;
110  });
111  if (Found == LookupRes.end())
112  return nullptr;
113 
114  return cast<FunctionDecl>(*Found);
115 }
116 
117 void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D,
118  AnalysisManager &Mgr, BugReporter &BR) const {
119  // Try to find an usable `errno` value.
120  // It can be an external variable called "errno" or a function that returns a
121  // pointer to the "errno" value. This function can have different names.
122  // The actual case is dependent on the C library implementation, we
123  // can only search for a match in one of these variations.
124  // We assume that exactly one of these cases might be true.
125  ErrnoDecl = getErrnoVar(Mgr.getASTContext());
126  if (!ErrnoDecl)
127  ErrnoDecl = getErrnoFunc(Mgr.getASTContext());
128 }
129 
130 void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
131  if (!C.inTopFrame())
132  return;
133 
134  ASTContext &ACtx = C.getASTContext();
135  ProgramStateRef State = C.getState();
136 
137  if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
138  // There is an external 'errno' variable.
139  // Use its memory region.
140  // The memory region for an 'errno'-like variable is allocated in system
141  // space by MemRegionManager.
142  const MemRegion *ErrnoR =
143  State->getRegion(ErrnoVar, C.getLocationContext());
144  assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
145  State = State->set<ErrnoRegion>(ErrnoR);
146  State =
148  C.addTransition(State);
149  } else if (ErrnoDecl) {
150  assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function.");
151  // There is a function that returns the location of 'errno'.
152  // We must create a memory region for it in system space.
153  // Currently a symbolic region is used with an artifical symbol.
154  // FIXME: It is better to have a custom (new) kind of MemRegion for such
155  // cases.
156  SValBuilder &SVB = C.getSValBuilder();
157  MemRegionManager &RMgr = C.getStateManager().getRegionManager();
158 
159  const MemSpaceRegion *GlobalSystemSpace =
160  RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
161 
162  // Create an artifical symbol for the region.
163  // It is not possible to associate a statement or expression in this case.
164  const SymbolConjured *Sym = SVB.conjureSymbol(
165  nullptr, C.getLocationContext(),
166  ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
167 
168  // The symbolic region is untyped, create a typed sub-region in it.
169  // The ElementRegion is used to make the errno region a typed region.
170  const MemRegion *ErrnoR = RMgr.getElementRegion(
171  ACtx.IntTy, SVB.makeZeroArrayIndex(),
172  RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext());
173  State = State->set<ErrnoRegion>(ErrnoR);
174  State =
176  C.addTransition(State);
177  }
178 }
179 
180 bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
181  // Return location of "errno" at a call to an "errno address returning"
182  // function.
183  if (ErrnoLocationCalls.contains(Call)) {
184  ProgramStateRef State = C.getState();
185 
186  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
187  if (!ErrnoR)
188  return false;
189 
190  State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
191  loc::MemRegionVal{ErrnoR});
192  C.addTransition(State);
193  return true;
194  }
195 
196  return false;
197 }
198 
199 void ErrnoModeling::checkLiveSymbols(ProgramStateRef State,
200  SymbolReaper &SR) const {
201  // The special errno region should never garbage collected.
202  if (const auto *ErrnoR = State->get<ErrnoRegion>())
203  SR.markLive(ErrnoR);
204 }
205 
206 namespace clang {
207 namespace ento {
208 namespace errno_modeling {
209 
211  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
212  if (!ErrnoR)
213  return {};
214  QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
215  return State->getSVal(ErrnoR, IntTy);
216 }
217 
219  const LocationContext *LCtx, SVal Value,
220  ErrnoCheckState EState) {
221  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
222  if (!ErrnoR)
223  return State;
224  // First set the errno value, the old state is still available at 'checkBind'
225  // or 'checkLocation' for errno value.
226  State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
227  return State->set<ErrnoState>(EState);
228 }
229 
231  uint64_t Value, ErrnoCheckState EState) {
232  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
233  if (!ErrnoR)
234  return State;
235  State = State->bindLoc(
236  loc::MemRegionVal{ErrnoR},
237  C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
238  C.getLocationContext());
239  return State->set<ErrnoState>(EState);
240 }
241 
243  const MemRegion *ErrnoR = State->get<ErrnoRegion>();
244  if (!ErrnoR)
245  return {};
246  return loc::MemRegionVal{ErrnoR};
247 }
248 
250  return State->set<ErrnoState>(EState);
251 }
252 
254  return State->get<ErrnoState>();
255 }
256 
257 bool isErrno(const Decl *D) {
258  if (const auto *VD = dyn_cast_or_null<VarDecl>(D))
259  if (const IdentifierInfo *II = VD->getIdentifier())
260  return II->getName() == ErrnoVarName;
261  if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
262  if (const IdentifierInfo *II = FD->getIdentifier())
263  return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
264  return false;
265 }
266 
267 const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
268  return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
269  const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
270  if (ErrnoR && BR.isInteresting(ErrnoR)) {
271  BR.markNotInteresting(ErrnoR);
272  return Message;
273  }
274  return "";
275  });
276 }
277 
278 } // namespace errno_modeling
279 } // namespace ento
280 } // namespace clang
281 
282 void ento::registerErrnoModeling(CheckerManager &mgr) {
283  mgr.registerChecker<ErrnoModeling>();
284 }
285 
286 bool ento::shouldRegisterErrnoModeling(const CheckerManager &mgr) {
287  return true;
288 }
clang::LocationContext
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Definition: AnalysisDeclContext.h:215
CallDescription.h
SVals.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::ento::errno_modeling::Irrelevant
@ Irrelevant
We do not know anything about 'errno'.
Definition: ErrnoModeling.h:26
llvm::SmallVector
Definition: LLVM.h:38
clang::IdentifierTable::get
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Definition: IdentifierTable.h:596
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:731
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
llvm::Optional
Definition: LLVM.h:40
getErrnoFunc
static const FunctionDecl * getErrnoFunc(ASTContext &ACtx)
Search for a function with a specific name that is used to return a pointer to "errno".
Definition: ErrnoModeling.cpp:96
clang::index::SymbolRole::Call
@ Call
ErrnoModeling.h
clang::ento::loc::MemRegionVal
Definition: SVals.h:502
clang::ASTContext::getSourceManager
SourceManager & getSourceManager()
Definition: ASTContext.h:716
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1078
getErrnoVar
static const VarDecl * getErrnoVar(ASTContext &ACtx)
Store a MemRegion that contains the 'errno' integer value.
Definition: ErrnoModeling.cpp:77
REGISTER_TRAIT_WITH_PROGRAMSTATE
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Definition: ProgramStateTrait.h:34
ParentMapContext.h
clang::ento::MemRegion
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:95
uint64_t
unsigned long uint64_t
Definition: hlsl_basic_types.h:24
clang::TranslationUnitDecl
The top declaration context.
Definition: Decl.h:80
BuiltinCheckerRegistration.h
clang::ento::errno_modeling::getErrnoNoteTag
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,...
Definition: ErrnoModeling.cpp:267
CheckerManager.h
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:208
clang::ento::PathSensitiveBugReport::getErrorNode
const ExplodedNode * getErrorNode() const
Definition: BugReporter.h:402
clang::ento::errno_modeling::setErrnoState
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
Definition: ErrnoModeling.cpp:249
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:874
clang::ento::errno_modeling::setErrnoValue
ProgramStateRef setErrnoValue(ProgramStateRef State, const LocationContext *LCtx, SVal Value, ErrnoCheckState EState)
Set value of 'errno' to any SVal, if possible.
Definition: ErrnoModeling.cpp:218
clang::ento::errno_modeling::ErrnoCheckState
ErrnoCheckState
Definition: ErrnoModeling.h:24
clang::ento::errno_modeling::getErrnoValue
Optional< SVal > getErrnoValue(ProgramStateRef State)
Returns the value of 'errno', if 'errno' was found in the AST.
Definition: ErrnoModeling.cpp:210
clang::ASTContext::IntTy
CanQualType IntTy
Definition: ASTContext.h:1105
clang::ento::errno_modeling::isErrno
bool isErrno(const Decl *D)
Determine if a Decl node related to 'errno'.
Definition: ErrnoModeling.cpp:257
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:655
Value
Value
Definition: UninitializedValues.cpp:102
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
State
LineState State
Definition: UnwrappedLineFormatter.cpp:1126
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
CheckerContext.h
clang::ASTContext::getLValueReferenceType
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
Definition: ASTContext.cpp:3405
ProgramState.h
Checker.h
clang::ento::PathSensitiveBugReport
Definition: BugReporter.h:289
clang
Definition: CalledOnceCheck.h:17
clang::DeclContext::lookup
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1662
clang::SourceManager::isInSystemHeader
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
Definition: SourceManager.h:1502
clang::ento::errno_modeling::getErrnoLoc
Optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
Definition: ErrnoModeling.cpp:242
clang::ento::CheckerContext
Definition: CheckerContext.h:23
clang::ento::PathSensitiveBugReport::isInteresting
bool isInteresting(SymbolRef sym) const
Definition: BugReporter.cpp:2369
clang::ASTContext::getPointerType
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
Definition: ASTContext.cpp:3285
clang::ento::SVal
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:74
clang::ento::errno_modeling::setErrnoValue
ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C, uint64_t Value, ErrnoCheckState EState)
Set value of 'errno' to a concrete (signed) integer, if possible.
Definition: ErrnoModeling.cpp:230
clang::ento::errno_modeling::getErrnoState
ErrnoCheckState getErrnoState(ProgramStateRef State)
Returns the errno check state, Errno_Irrelevant if 'errno' was not found (this is not the only case f...
Definition: ErrnoModeling.cpp:253
clang::ento::NoteTag
The tag upon which the TagVisitor reacts.
Definition: BugReporter.h:763
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1872
llvm::IntrusiveRefCntPtr
Definition: LLVM.h:47