clang  10.0.0git
FuchsiaHandleChecker.cpp
Go to the documentation of this file.
1 //=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- 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 checker checks if the handle of Fuchsia is properly used according to
10 // following rules.
11 // - If a handle is acquired, it should be released before execution
12 // ends.
13 // - If a handle is released, it should not be released again.
14 // - If a handle is released, it should not be used for other purposes
15 // such as I/O.
16 //
17 // In this checker, each tracked handle is associated with a state. When the
18 // handle variable is passed to different function calls or syscalls, its state
19 // changes. The state changes can be generally represented by following ASCII
20 // Art:
21 //
22 //
23 // +-+---------v-+ +------------+
24 // acquire_func succeeded | | Escape | |
25 // +-----------------> Allocated +---------> Escaped <--+
26 // | | | | | |
27 // | +-----+------++ +------------+ |
28 // | | | |
29 // | release_func | +--+ |
30 // | | | handle +--------+ |
31 // | | | dies | | |
32 // | +----v-----+ +---------> Leaked | |
33 // | | | |(REPORT)| |
34 // +----------+--+ | Released | Escape +--------+ |
35 // | | | +---------------------------+
36 // | Not tracked <--+ +----+---+-+
37 // | | | | | As argument by value
38 // +------+------+ | release_func | +------+ in function call
39 // | | | | or by reference in
40 // | | | | use_func call
41 // +---------+ +----v-----+ | +-----------+
42 // acquire_func failed | Double | +-----> Use after |
43 // | released | | released |
44 // | (REPORT) | | (REPORT) |
45 // +----------+ +-----------+
46 //
47 // acquire_func represents the functions or syscalls that may acquire a handle.
48 // release_func represents the functions or syscalls that may release a handle.
49 // use_func represents the functions or syscall that requires an open handle.
50 //
51 // If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
52 // is properly used. Otherwise a bug and will be reported.
53 //
54 // Note that, the analyzer does not always know for sure if a function failed
55 // or succeeded. In those cases we use the state MaybeAllocated.
56 // Thus, the diagramm above captures the intent, not implementation details.
57 //
58 // Due to the fact that the number of handle related syscalls in Fuchsia
59 // is large, we adopt the annotation attributes to descript syscalls'
60 // operations(acquire/release/use) on handles instead of hardcoding
61 // everything in the checker.
62 //
63 // We use following annotation attributes for handle related syscalls or
64 // functions:
65 // 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
66 // 2. __attribute__((release_handle("Fuchsia"))) |handle will be released
67 // 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
68 // escaped state, it also needs to be open.
69 //
70 // For example, an annotated syscall:
71 // zx_status_t zx_channel_create(
72 // uint32_t options,
73 // zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
74 // zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
75 // denotes a syscall which will acquire two handles and save them to 'out0' and
76 // 'out1' when succeeded.
77 //
78 //===----------------------------------------------------------------------===//
79 
80 #include "clang/AST/Attr.h"
81 #include "clang/AST/Decl.h"
82 #include "clang/AST/Type.h"
93 
94 using namespace clang;
95 using namespace ento;
96 
97 namespace {
98 
99 static const StringRef HandleTypeName = "zx_handle_t";
100 static const StringRef ErrorTypeName = "zx_status_t";
101 
102 class HandleState {
103 private:
104  enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K;
105  SymbolRef ErrorSym;
106  HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
107 
108 public:
109  bool operator==(const HandleState &Other) const {
110  return K == Other.K && ErrorSym == Other.ErrorSym;
111  }
112  bool isAllocated() const { return K == Kind::Allocated; }
113  bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
114  bool isReleased() const { return K == Kind::Released; }
115  bool isEscaped() const { return K == Kind::Escaped; }
116 
117  static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
118  return HandleState(Kind::MaybeAllocated, ErrorSym);
119  }
120  static HandleState getAllocated(ProgramStateRef State, HandleState S) {
121  assert(S.maybeAllocated());
122  assert(State->getConstraintManager()
123  .isNull(State, S.getErrorSym())
124  .isConstrained());
125  return HandleState(Kind::Allocated, nullptr);
126  }
127  static HandleState getReleased() {
128  return HandleState(Kind::Released, nullptr);
129  }
130  static HandleState getEscaped() {
131  return HandleState(Kind::Escaped, nullptr);
132  }
133 
134  SymbolRef getErrorSym() const { return ErrorSym; }
135 
136  void Profile(llvm::FoldingSetNodeID &ID) const {
137  ID.AddInteger(static_cast<int>(K));
138  ID.AddPointer(ErrorSym);
139  }
140 
141  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
142  switch (K) {
143 #define CASE(ID) \
144  case ID: \
145  OS << #ID; \
146  break;
147  CASE(Kind::MaybeAllocated)
148  CASE(Kind::Allocated)
149  CASE(Kind::Released)
150  CASE(Kind::Escaped)
151  }
152  }
153 
154  LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
155 };
156 
157 template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
158  return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
159 }
160 
161 class FuchsiaHandleChecker
162  : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
163  check::PointerEscape, eval::Assume> {
164  BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
165  /*SuppressOnSink=*/true};
166  BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
167  "Fuchsia Handle Error"};
168  BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
169  "Fuchsia Handle Error"};
170 
171 public:
172  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
173  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
174  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
175  ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
176  bool Assumption) const;
177  ProgramStateRef checkPointerEscape(ProgramStateRef State,
178  const InvalidatedSymbols &Escaped,
179  const CallEvent *Call,
180  PointerEscapeKind Kind) const;
181 
182  ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
183  CheckerContext &C, ExplodedNode *Pred) const;
184 
185  void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
186  CheckerContext &C) const;
187 
188  void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
189  CheckerContext &C) const;
190 
191  void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
192  const SourceRange *Range, const BugType &Type,
193  StringRef Msg) const;
194 
195  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
196  const char *Sep) const override;
197 };
198 } // end anonymous namespace
199 
200 REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
201 
202 static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
203  CheckerContext &Ctx) {
204  ProgramStateRef State = N->getState();
205  // When bug type is handle leak, exploded node N does not have state info for
206  // leaking handle. Get the predecessor of N instead.
207  if (!State->get<HStateMap>(Sym))
208  N = N->getFirstPred();
209 
210  const ExplodedNode *Pred = N;
211  while (N) {
212  State = N->getState();
213  if (!State->get<HStateMap>(Sym)) {
214  const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
215  if (HState && (HState->isAllocated() || HState->maybeAllocated()))
216  return N;
217  }
218  Pred = N;
219  N = N->getFirstPred();
220  }
221  return nullptr;
222 }
223 
224 /// Returns the symbols extracted from the argument or null if it cannot be
225 /// found.
227  ProgramStateRef State) {
228  int PtrToHandleLevel = 0;
229  while (QT->isAnyPointerType() || QT->isReferenceType()) {
230  ++PtrToHandleLevel;
231  QT = QT->getPointeeType();
232  }
233  if (const auto *HandleType = QT->getAs<TypedefType>()) {
234  if (HandleType->getDecl()->getName() != HandleTypeName)
235  return nullptr;
236  if (PtrToHandleLevel > 1) {
237  // Not supported yet.
238  return nullptr;
239  }
240 
241  if (PtrToHandleLevel == 0) {
242  return Arg.getAsSymbol();
243  } else {
244  assert(PtrToHandleLevel == 1);
245  if (Optional<Loc> ArgLoc = Arg.getAs<Loc>())
246  return State->getSVal(*ArgLoc).getAsSymbol();
247  }
248  }
249  return nullptr;
250 }
251 
252 void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
253  CheckerContext &C) const {
254  ProgramStateRef State = C.getState();
255  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
256  if (!FuncDecl) {
257  // Unknown call, escape by value handles. They are not covered by
258  // PointerEscape callback.
259  for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
260  if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
261  State = State->set<HStateMap>(Handle, HandleState::getEscaped());
262  }
263  C.addTransition(State);
264  return;
265  }
266 
267  for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
268  if (Arg >= FuncDecl->getNumParams())
269  break;
270  const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
271  SymbolRef Handle =
272  getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
273  if (!Handle)
274  continue;
275 
276  // Handled in checkPostCall.
277  if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
278  hasFuchsiaAttr<AcquireHandleAttr>(PVD))
279  continue;
280 
281  const HandleState *HState = State->get<HStateMap>(Handle);
282  if (!HState || HState->isEscaped())
283  continue;
284 
285  if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) {
286  if (HState->isReleased()) {
287  reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
288  return;
289  }
290  }
291  if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
292  PVD->getType()->isIntegerType()) {
293  // Working around integer by-value escapes.
294  State = State->set<HStateMap>(Handle, HandleState::getEscaped());
295  }
296  }
297  C.addTransition(State);
298 }
299 
300 void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
301  CheckerContext &C) const {
302  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
303  if (!FuncDecl)
304  return;
305 
306  ProgramStateRef State = C.getState();
307 
308  std::vector<std::function<std::string(BugReport & BR)>> Notes;
309  SymbolRef ResultSymbol = nullptr;
310  if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
311  if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
312  ResultSymbol = Call.getReturnValue().getAsSymbol();
313 
314  // Function returns an open handle.
315  if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
316  SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
317  State =
318  State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
319  }
320 
321  for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
322  if (Arg >= FuncDecl->getNumParams())
323  break;
324  const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
325  SymbolRef Handle =
326  getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
327  if (!Handle)
328  continue;
329 
330  const HandleState *HState = State->get<HStateMap>(Handle);
331  if (HState && HState->isEscaped())
332  continue;
333  if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
334  if (HState && HState->isReleased()) {
335  reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
336  return;
337  } else {
338  Notes.push_back([Handle](BugReport &BR) {
339  auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
340  if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
341  return "Handle released here.";
342  } else
343  return "";
344  });
345  State = State->set<HStateMap>(Handle, HandleState::getReleased());
346  }
347  } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
348  Notes.push_back([Handle](BugReport &BR) {
349  auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
350  if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
351  return "Handle allocated here.";
352  } else
353  return "";
354  });
355  State = State->set<HStateMap>(
356  Handle, HandleState::getMaybeAllocated(ResultSymbol));
357  }
358  }
359  const NoteTag *T = nullptr;
360  if (!Notes.empty()) {
361  T = C.getNoteTag(
362  [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string {
363  if (&BR.getBugType() != &UseAfterReleaseBugType &&
364  &BR.getBugType() != &LeakBugType &&
365  &BR.getBugType() != &DoubleReleaseBugType)
366  return "";
367  for (auto &Note : Notes) {
368  std::string Text = Note(BR);
369  if (!Text.empty())
370  return Text;
371  }
372  return "";
373  });
374  }
375  C.addTransition(State, T);
376 }
377 
378 void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
379  CheckerContext &C) const {
380  ProgramStateRef State = C.getState();
381  SmallVector<SymbolRef, 2> LeakedSyms;
382  HStateMapTy TrackedHandles = State->get<HStateMap>();
383  for (auto &CurItem : TrackedHandles) {
384  if (!SymReaper.isDead(CurItem.first))
385  continue;
386  if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
387  LeakedSyms.push_back(CurItem.first);
388  State = State->remove<HStateMap>(CurItem.first);
389  }
390 
391  ExplodedNode *N = C.getPredecessor();
392  if (!LeakedSyms.empty())
393  N = reportLeaks(LeakedSyms, C, N);
394 
395  C.addTransition(State, N);
396 }
397 
398 // Acquiring a handle is not always successful. In Fuchsia most functions
399 // return a status code that determines the status of the handle.
400 // When we split the path based on this status code we know that on one
401 // path we do have the handle and on the other path the acquire failed.
402 // This method helps avoiding false positive leak warnings on paths where
403 // the function failed.
404 // Moreover, when a handle is known to be zero (the invalid handle),
405 // we no longer can follow the symbol on the path, becaue the constant
406 // zero will be used instead of the symbol. We also do not need to release
407 // an invalid handle, so we remove the corresponding symbol from the state.
408 ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
409  SVal Cond,
410  bool Assumption) const {
411  // TODO: add notes about successes/fails for APIs.
412  ConstraintManager &Cmr = State->getConstraintManager();
413  HStateMapTy TrackedHandles = State->get<HStateMap>();
414  for (auto &CurItem : TrackedHandles) {
415  ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
416  if (HandleVal.isConstrainedTrue()) {
417  // The handle is invalid. We can no longer follow the symbol on this path.
418  State = State->remove<HStateMap>(CurItem.first);
419  }
420  SymbolRef ErrorSym = CurItem.second.getErrorSym();
421  if (!ErrorSym)
422  continue;
423  ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
424  if (ErrorVal.isConstrainedTrue()) {
425  // Allocation succeeded.
426  if (CurItem.second.maybeAllocated())
427  State = State->set<HStateMap>(
428  CurItem.first, HandleState::getAllocated(State, CurItem.second));
429  } else if (ErrorVal.isConstrainedFalse()) {
430  // Allocation failed.
431  if (CurItem.second.maybeAllocated())
432  State = State->remove<HStateMap>(CurItem.first);
433  }
434  }
435  return State;
436 }
437 
438 ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
439  ProgramStateRef State, const InvalidatedSymbols &Escaped,
440  const CallEvent *Call, PointerEscapeKind Kind) const {
441  const FunctionDecl *FuncDecl =
442  Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
443 
444  llvm::DenseSet<SymbolRef> UnEscaped;
445  // Not all calls should escape our symbols.
446  if (FuncDecl &&
447  (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
448  Kind == PSK_EscapeOutParameters)) {
449  for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
450  if (Arg >= FuncDecl->getNumParams())
451  break;
452  const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
453  SymbolRef Handle =
454  getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State);
455  if (!Handle)
456  continue;
457  if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
458  hasFuchsiaAttr<ReleaseHandleAttr>(PVD))
459  UnEscaped.insert(Handle);
460  }
461  }
462 
463  // For out params, we have to deal with derived symbols. See
464  // MacOSKeychainAPIChecker for details.
465  for (auto I : State->get<HStateMap>()) {
466  if (Escaped.count(I.first) && !UnEscaped.count(I.first))
467  State = State->set<HStateMap>(I.first, HandleState::getEscaped());
468  if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
469  auto ParentSym = SD->getParentSymbol();
470  if (Escaped.count(ParentSym))
471  State = State->set<HStateMap>(I.first, HandleState::getEscaped());
472  }
473  }
474 
475  return State;
476 }
477 
478 ExplodedNode *
479 FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
480  CheckerContext &C, ExplodedNode *Pred) const {
481  ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
482  for (SymbolRef LeakedHandle : LeakedHandles) {
483  reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
484  "Potential leak of handle");
485  }
486  return ErrNode;
487 }
488 
489 void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
490  const SourceRange &Range,
491  CheckerContext &C) const {
492  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
493  reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
494  "Releasing a previously released handle");
495 }
496 
497 void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
498  const SourceRange &Range,
499  CheckerContext &C) const {
500  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
501  reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
502  "Using a previously released handle");
503 }
504 
505 void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
506  CheckerContext &C,
507  const SourceRange *Range,
508  const BugType &Type, StringRef Msg) const {
509  if (!ErrorNode)
510  return;
511 
512  std::unique_ptr<PathSensitiveBugReport> R;
513  if (Type.isSuppressOnSink()) {
514  const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
515  if (AcquireNode) {
516  PathDiagnosticLocation LocUsedForUniqueing =
518  AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
519  AcquireNode->getLocationContext());
520 
521  R = std::make_unique<PathSensitiveBugReport>(
522  Type, Msg, ErrorNode, LocUsedForUniqueing,
523  AcquireNode->getLocationContext()->getDecl());
524  }
525  }
526  if (!R)
527  R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
528  if (Range)
529  R->addRange(*Range);
530  R->markInteresting(Sym);
531  C.emitReport(std::move(R));
532 }
533 
534 void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
535  mgr.registerChecker<FuchsiaHandleChecker>();
536 }
537 
538 bool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) {
539  return true;
540 }
541 
542 void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
543  const char *NL, const char *Sep) const {
544 
545  HStateMapTy StateMap = State->get<HStateMap>();
546 
547  if (!StateMap.isEmpty()) {
548  Out << Sep << "FuchsiaHandleChecker :" << NL;
549  for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
550  ++I) {
551  I.getKey()->dumpToStream(Out);
552  Out << " : ";
553  I.getData().dump(Out);
554  Out << NL;
555  }
556  }
557 }
Represents a function declaration or definition.
Definition: Decl.h:1783
A (possibly-)qualified type.
Definition: Type.h:654
bool operator==(CanQual< T > x, CanQual< U > y)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
C Language Family Type Representation.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The pointer has been passed to a function indirectly.
The base class of the type hierarchy.
Definition: Type.h:1450
QualType getReturnType() const
Definition: Decl.h:2445
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:7002
Represents a parameter to a function.
Definition: Decl.h:1595
const SymExpr * SymbolRef
Definition: SymExpr.h:110
LineState State
#define CASE(ID)
bool isReferenceType() const
Definition: Type.h:6516
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Escape for a new symbol that was generated into a region that the analyzer cannot follow during a con...
bool hasAttr() const
Definition: DeclBase.h:542
static SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg, ProgramStateRef State)
Returns the symbols extracted from the argument or null if it cannot be found.
The pointer has been passed to a function call directly.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Kind
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2422
bool isAnyPointerType() const
Definition: Type.h:6508
static const ExplodedNode * getAcquireSite(const ExplodedNode *N, SymbolRef Sym, CheckerContext &Ctx)
Dataflow Directional Tag Classes.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:6811
T * getAttr() const
Definition: DeclBase.h:538
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
StringRef Text
Definition: Format.cpp:1826
QualType getType() const
Definition: Decl.h:630
A trivial tuple used to represent a source range.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3242
Attr - This represents one attribute.
Definition: Attr.h:45