FuchsiaHandleChecker.cpp revision 360784
1139823Simp//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=//
21541Srgrimes//
31541Srgrimes// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4137668Smlaier// See https://llvm.org/LICENSE.txt for license information.
51541Srgrimes// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61541Srgrimes//
71541Srgrimes//===----------------------------------------------------------------------===//
81541Srgrimes//
91541Srgrimes// This checker checks if the handle of Fuchsia is properly used according to
101541Srgrimes// following rules.
111541Srgrimes//   - If a handle is acquired, it should be released before execution
121541Srgrimes//        ends.
131541Srgrimes//   - If a handle is released, it should not be released again.
141541Srgrimes//   - If a handle is released, it should not be used for other purposes
151541Srgrimes//        such as I/O.
161541Srgrimes//
171541Srgrimes// In this checker, each tracked handle is associated with a state. When the
181541Srgrimes// handle variable is passed to different function calls or syscalls, its state
191541Srgrimes// changes. The state changes can be generally represented by following ASCII
201541Srgrimes// Art:
211541Srgrimes//
221541Srgrimes//
231541Srgrimes//                              +-+---------v-+         +------------+
241541Srgrimes//       acquire_func succeeded |             | Escape  |            |
251541Srgrimes//            +----------------->  Allocated  +--------->  Escaped   <--+
261541Srgrimes//            |                 |             |         |            |  |
271541Srgrimes//            |                 +-----+------++         +------------+  |
281541Srgrimes//            |                       |      |                          |
291541Srgrimes//            |         release_func  |      +--+                       |
3010939Swollman//            |                       |         | handle  +--------+    |
311541Srgrimes//            |                       |         | dies    |        |    |
321541Srgrimes//            |                  +----v-----+   +---------> Leaked |    |
33172467Ssilby//            |                  |          |             |(REPORT)|    |
34172467Ssilby// +----------+--+               | Released | Escape      +--------+    |
35172467Ssilby// |             |               |          +---------------------------+
36204902Sqingli// | Not tracked <--+            +----+---+-+
37143868Sglebius// |             |  |                 |   |        As argument by value
381541Srgrimes// +------+------+  |    release_func |   +------+ in function call
391549Srgrimes//        |         |                 |          | or by reference in
4024204Sbde//        |         |                 |          | use_func call
411541Srgrimes//        +---------+            +----v-----+    |     +-----------+
42164033Srwatson//        acquire_func failed    | Double   |    +-----> Use after |
431541Srgrimes//                               | released |          | released  |
44186948Sbz//                               | (REPORT) |          | (REPORT)  |
4512704Sphk//                               +----------+          +-----------+
46186948Sbz//
4712704Sphk// acquire_func represents the functions or syscalls that may acquire a handle.
48192011Sqingli// release_func represents the functions or syscalls that may release a handle.
491541Srgrimes// use_func represents the functions or syscall that requires an open handle.
501541Srgrimes//
51195914Sqingli// If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
52215207Sgnn// is properly used. Otherwise a bug and will be reported.
53192011Sqingli//
54186119Sqingli// Note that, the analyzer does not always know for sure if a function failed
5555009Sshin// or succeeded. In those cases we use the state MaybeAllocated.
561541Srgrimes// Thus, the diagramm above captures the intent, not implementation details.
57192011Sqingli//
581541Srgrimes// Due to the fact that the number of handle related syscalls in Fuchsia
591541Srgrimes// is large, we adopt the annotation attributes to descript syscalls'
601541Srgrimes// operations(acquire/release/use) on handles instead of hardcoding
6181127Sume// everything in the checker.
62170613Sbms//
63189592Sbms// We use following annotation attributes for handle related syscalls or
64195699Srwatson// functions:
65195699Srwatson//  1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
661541Srgrimes//  2. __attribute__((release_handle("Fuchsia"))) |handle will be released
6792723Salfred//  3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
6892723Salfred//     escaped state, it also needs to be open.
6992723Salfred//
7092723Salfred// For example, an annotated syscall:
7155009Sshin//   zx_status_t zx_channel_create(
72137628Smlaier//   uint32_t options,
73222143Sqingli//   zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
7492723Salfred//   zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
7592723Salfred// denotes a syscall which will acquire two handles and save them to 'out0' and
76228313Sglebius// 'out1' when succeeded.
77167729Sbms//
781541Srgrimes//===----------------------------------------------------------------------===//
79215701Sdim
80207369Sbz#include "clang/AST/Attr.h"
81195699Srwatson#include "clang/AST/Decl.h"
82195699Srwatson#include "clang/AST/Type.h"
83149221Sglebius#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
8421666Swollman#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
85207369Sbz#include "clang/StaticAnalyzer/Core/Checker.h"
86207369Sbz#include "clang/StaticAnalyzer/Core/CheckerManager.h"
87207369Sbz#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
88215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
89215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
90215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
911541Srgrimes#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
921541Srgrimes#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
93226401Sglebius
941541Srgrimesusing namespace clang;
951549Srgrimesusing namespace ento;
96169454Srwatson
971541Srgrimesnamespace {
981541Srgrimes
991541Srgrimesstatic const StringRef HandleTypeName = "zx_handle_t";
1001541Srgrimesstatic const StringRef ErrorTypeName = "zx_status_t";
101194951Srwatson
102226401Sglebiusclass HandleState {
103226401Sglebiusprivate:
104226401Sglebius  enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K;
105226401Sglebius  SymbolRef ErrorSym;
106194951Srwatson  HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
1071541Srgrimes
108194951Srwatsonpublic:
1091541Srgrimes  bool operator==(const HandleState &Other) const {
1101541Srgrimes    return K == Other.K && ErrorSym == Other.ErrorSym;
1111541Srgrimes  }
1121541Srgrimes  bool isAllocated() const { return K == Kind::Allocated; }
113133486Sandre  bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
114133486Sandre  bool isReleased() const { return K == Kind::Released; }
115133486Sandre  bool isEscaped() const { return K == Kind::Escaped; }
116133486Sandre
117169454Srwatson  static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
118133486Sandre    return HandleState(Kind::MaybeAllocated, ErrorSym);
119133486Sandre  }
120133486Sandre  static HandleState getAllocated(ProgramStateRef State, HandleState S) {
121194951Srwatson    assert(S.maybeAllocated());
122133486Sandre    assert(State->getConstraintManager()
123194951Srwatson               .isNull(State, S.getErrorSym())
124194951Srwatson               .isConstrained());
125184295Sbz    return HandleState(Kind::Allocated, nullptr);
126194951Srwatson  }
127133486Sandre  static HandleState getReleased() {
128194951Srwatson    return HandleState(Kind::Released, nullptr);
129184295Sbz  }
130133486Sandre  static HandleState getEscaped() {
131133486Sandre    return HandleState(Kind::Escaped, nullptr);
132133486Sandre  }
1331541Srgrimes
1341541Srgrimes  SymbolRef getErrorSym() const { return ErrorSym; }
1351541Srgrimes
1361541Srgrimes  void Profile(llvm::FoldingSetNodeID &ID) const {
1371549Srgrimes    ID.AddInteger(static_cast<int>(K));
138169454Srwatson    ID.AddPointer(ErrorSym);
1391541Srgrimes  }
1401541Srgrimes
1411541Srgrimes  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
1421541Srgrimes    switch (K) {
143166450Sbms#define CASE(ID)                                                               \
1441541Srgrimes  case ID:                                                                     \
1451541Srgrimes    OS << #ID;                                                                 \
1461541Srgrimes    break;
1471541Srgrimes      CASE(Kind::MaybeAllocated)
1481541Srgrimes      CASE(Kind::Allocated)
1491541Srgrimes      CASE(Kind::Released)
1501541Srgrimes      CASE(Kind::Escaped)
1511541Srgrimes    }
1521541Srgrimes  }
1531541Srgrimes
1541541Srgrimes  LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
1551541Srgrimes};
15612296Sphk
157169454Srwatsontemplate <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
1581541Srgrimes  return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
1591541Srgrimes}
1601541Srgrimes
1611541Srgrimesclass FuchsiaHandleChecker
1621541Srgrimes    : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
1634127Swollman                     check::PointerEscape, eval::Assume> {
164133874Srwatson  BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
1651541Srgrimes                      /*SuppressOnSink=*/true};
1661541Srgrimes  BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
1671541Srgrimes                               "Fuchsia Handle Error"};
1681541Srgrimes  BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
1691541Srgrimes                                 "Fuchsia Handle Error"};
17055009Sshin
17155009Sshinpublic:
17255009Sshin  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
17355009Sshin  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
17455009Sshin  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
17555009Sshin  ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
17655009Sshin                             bool Assumption) const;
17755009Sshin  ProgramStateRef checkPointerEscape(ProgramStateRef State,
17855009Sshin                                     const InvalidatedSymbols &Escaped,
17955009Sshin                                     const CallEvent *Call,
18055009Sshin                                     PointerEscapeKind Kind) const;
18155009Sshin
18255009Sshin  ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
18355009Sshin                            CheckerContext &C, ExplodedNode *Pred) const;
18455009Sshin
18555009Sshin  void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
18655009Sshin                           CheckerContext &C) const;
18755009Sshin
18855009Sshin  void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
189184295Sbz                          CheckerContext &C) const;
19055009Sshin
19155009Sshin  void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
19255009Sshin                 const SourceRange *Range, const BugType &Type,
193169454Srwatson                 StringRef Msg) const;
19455009Sshin
19555009Sshin  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
19655009Sshin                  const char *Sep) const override;
19755009Sshin};
19855009Sshin} // end anonymous namespace
19955009Sshin
20055009SshinREGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
20155009Sshin
20255009Sshinstatic const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
20355009Sshin                                          CheckerContext &Ctx) {
20455009Sshin  ProgramStateRef State = N->getState();
20555009Sshin  // When bug type is handle leak, exploded node N does not have state info for
2061541Srgrimes  // leaking handle. Get the predecessor of N instead.
2071541Srgrimes  if (!State->get<HStateMap>(Sym))
208191443Srwatson    N = N->getFirstPred();
209191443Srwatson
2101541Srgrimes  const ExplodedNode *Pred = N;
2111541Srgrimes  while (N) {
2121549Srgrimes    State = N->getState();
213169454Srwatson    if (!State->get<HStateMap>(Sym)) {
214169454Srwatson      const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
2151541Srgrimes      if (HState && (HState->isAllocated() || HState->maybeAllocated()))
2161541Srgrimes        return N;
217184295Sbz    }
2181541Srgrimes    Pred = N;
219168032Sbms    N = N->getFirstPred();
22084102Sjlemon  }
221189592Sbms  return nullptr;
2221541Srgrimes}
2231541Srgrimes
224194951Srwatson/// Returns the symbols extracted from the argument or null if it cannot be
225168032Sbms/// found.
2261541Srgrimesstatic SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg,
227184295Sbz                                        ProgramStateRef State) {
228168032Sbms  int PtrToHandleLevel = 0;
22987124Sbrian  while (QT->isAnyPointerType() || QT->isReferenceType()) {
230168032Sbms    ++PtrToHandleLevel;
23187124Sbrian    QT = QT->getPointeeType();
232191443Srwatson  }
233191443Srwatson  if (const auto *HandleType = QT->getAs<TypedefType>()) {
234191443Srwatson    if (HandleType->getDecl()->getName() != HandleTypeName)
235191443Srwatson      return nullptr;
23655009Sshin    if (PtrToHandleLevel > 1) {
237191443Srwatson      // Not supported yet.
238191443Srwatson      return nullptr;
239191443Srwatson    }
240191443Srwatson
241227791Sglebius    if (PtrToHandleLevel == 0) {
242227791Sglebius      return Arg.getAsSymbol();
243227791Sglebius    } else {
244227791Sglebius      assert(PtrToHandleLevel == 1);
245227791Sglebius      if (Optional<Loc> ArgLoc = Arg.getAs<Loc>())
246227791Sglebius        return State->getSVal(*ArgLoc).getAsSymbol();
247227791Sglebius    }
248227791Sglebius  }
249227791Sglebius  return nullptr;
250227791Sglebius}
251227791Sglebius
252227831Sglebiusvoid FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
253227831Sglebius                                        CheckerContext &C) const {
254227791Sglebius  ProgramStateRef State = C.getState();
255227791Sglebius  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
256227791Sglebius  if (!FuncDecl) {
257227791Sglebius    // Unknown call, escape by value handles. They are not covered by
258227791Sglebius    // PointerEscape callback.
259227791Sglebius    for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
260227791Sglebius      if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
261227791Sglebius        State = State->set<HStateMap>(Handle, HandleState::getEscaped());
262227791Sglebius    }
263227791Sglebius    C.addTransition(State);
264227791Sglebius    return;
265227791Sglebius  }
266227791Sglebius
267191443Srwatson  for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
268191443Srwatson    if (Arg >= FuncDecl->getNumParams())
269191443Srwatson      break;
270191443Srwatson    const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
271227791Sglebius    SymbolRef Handle =
272227791Sglebius        getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
273227791Sglebius    if (!Handle)
274191443Srwatson      continue;
275191443Srwatson
27655009Sshin    // Handled in checkPostCall.
277164033Srwatson    if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
278164033Srwatson        hasFuchsiaAttr<AcquireHandleAttr>(PVD))
279164033Srwatson      continue;
280164033Srwatson
281164033Srwatson    const HandleState *HState = State->get<HStateMap>(Handle);
282184295Sbz    if (!HState || HState->isEscaped())
283184295Sbz      continue;
284164033Srwatson
285164033Srwatson    if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) {
28655009Sshin      if (HState->isReleased()) {
287164033Srwatson        reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
288164033Srwatson        return;
289164033Srwatson      }
290164033Srwatson    }
291164033Srwatson    if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
292184295Sbz        PVD->getType()->isIntegerType()) {
293184295Sbz      // Working around integer by-value escapes.
294164033Srwatson      State = State->set<HStateMap>(Handle, HandleState::getEscaped());
295164033Srwatson    }
29655009Sshin  }
297184295Sbz  C.addTransition(State);
298184295Sbz}
29983366Sjulian
300191443Srwatsonvoid FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
301191443Srwatson                                         CheckerContext &C) const {
302191443Srwatson  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
303191443Srwatson  if (!FuncDecl)
304191443Srwatson    return;
30555009Sshin
30655009Sshin  ProgramStateRef State = C.getState();
307191443Srwatson
308191443Srwatson  std::vector<std::function<std::string(BugReport & BR)>> Notes;
309191443Srwatson  SymbolRef ResultSymbol = nullptr;
3101541Srgrimes  if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
311191456Srwatson    if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
312191456Srwatson      ResultSymbol = Call.getReturnValue().getAsSymbol();
313191456Srwatson
314191456Srwatson  // Function returns an open handle.
315191456Srwatson  if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
316191456Srwatson    SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
317191456Srwatson    State =
318191456Srwatson        State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
319191456Srwatson  }
320191456Srwatson
321191456Srwatson  for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
322191456Srwatson    if (Arg >= FuncDecl->getNumParams())
323191456Srwatson      break;
324191456Srwatson    const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
325191456Srwatson    SymbolRef Handle =
326191456Srwatson        getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
327191456Srwatson    if (!Handle)
328191456Srwatson      continue;
329191456Srwatson
330191456Srwatson    const HandleState *HState = State->get<HStateMap>(Handle);
331191456Srwatson    if (HState && HState->isEscaped())
332191456Srwatson      continue;
333191456Srwatson    if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
334191456Srwatson      if (HState && HState->isReleased()) {
335191456Srwatson        reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
3361541Srgrimes        return;
33714632Sfenner      } else {
338191443Srwatson        Notes.push_back([Handle](BugReport &BR) {
339191443Srwatson          auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
3401541Srgrimes          if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
341191443Srwatson            return "Handle released here.";
342194951Srwatson          } else
343191443Srwatson            return "";
344191443Srwatson        });
345191443Srwatson        State = State->set<HStateMap>(Handle, HandleState::getReleased());
346191443Srwatson      }
347191443Srwatson    } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
348191443Srwatson      Notes.push_back([Handle](BugReport &BR) {
349191443Srwatson        auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
350191443Srwatson        if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
351191443Srwatson          return "Handle allocated here.";
352194760Srwatson        } else
353194760Srwatson          return "";
354194951Srwatson      });
355191443Srwatson      State = State->set<HStateMap>(
356194760Srwatson          Handle, HandleState::getMaybeAllocated(ResultSymbol));
357191443Srwatson    }
358191443Srwatson  }
359191443Srwatson  const NoteTag *T = nullptr;
360191443Srwatson  if (!Notes.empty()) {
361191443Srwatson    T = C.getNoteTag(
362191443Srwatson        [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string {
363191443Srwatson          if (&BR.getBugType() != &UseAfterReleaseBugType &&
364191443Srwatson              &BR.getBugType() != &LeakBugType &&
36584102Sjlemon              &BR.getBugType() != &DoubleReleaseBugType)
36684102Sjlemon            return "";
367191443Srwatson          for (auto &Note : Notes) {
368194760Srwatson            std::string Text = Note(BR);
369194760Srwatson            if (!Text.empty())
370194760Srwatson              return Text;
37184102Sjlemon          }
372191443Srwatson          return "";
373191443Srwatson        });
3741541Srgrimes  }
375191500Srwatson  C.addTransition(State, T);
3761541Srgrimes}
3771541Srgrimes
3781541Srgrimesvoid FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
379227958Sglebius                                            CheckerContext &C) const {
380194760Srwatson  ProgramStateRef State = C.getState();
381194760Srwatson  SmallVector<SymbolRef, 2> LeakedSyms;
382194951Srwatson  HStateMapTy TrackedHandles = State->get<HStateMap>();
38371999Sphk  for (auto &CurItem : TrackedHandles) {
3848071Swollman    if (!SymReaper.isDead(CurItem.first))
3858071Swollman      continue;
3868071Swollman    if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
3878071Swollman      LeakedSyms.push_back(CurItem.first);
3888071Swollman    State = State->remove<HStateMap>(CurItem.first);
389194760Srwatson  }
390194760Srwatson
391194760Srwatson  ExplodedNode *N = C.getPredecessor();
392194760Srwatson  if (!LeakedSyms.empty())
393194951Srwatson    N = reportLeaks(LeakedSyms, C, N);
3948876Srgrimes
3958071Swollman  C.addTransition(State, N);
3968071Swollman}
3978071Swollman
398191500Srwatson// Acquiring a handle is not always successful. In Fuchsia most functions
399194760Srwatson// return a status code that determines the status of the handle.
4008071Swollman// When we split the path based on this status code we know that on one
4011541Srgrimes// path we do have the handle and on the other path the acquire failed.
402191500Srwatson// This method helps avoiding false positive leak warnings on paths where
403191500Srwatson// the function failed.
404194760Srwatson// Moreover, when a handle is known to be zero (the invalid handle),
405191500Srwatson// we no longer can follow the symbol on the path, becaue the constant
4061541Srgrimes// zero will be used instead of the symbol. We also do not need to release
4071541Srgrimes// an invalid handle, so we remove the corresponding symbol from the state.
4081541SrgrimesProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
4091541Srgrimes                                                 SVal Cond,
410184295Sbz                                                 bool Assumption) const {
41120407Swollman  // TODO: add notes about successes/fails for APIs.
412191500Srwatson  ConstraintManager &Cmr = State->getConstraintManager();
413191500Srwatson  HStateMapTy TrackedHandles = State->get<HStateMap>();
414191500Srwatson  for (auto &CurItem : TrackedHandles) {
415191500Srwatson    ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
416194760Srwatson    if (HandleVal.isConstrainedTrue()) {
417191500Srwatson      // The handle is invalid. We can no longer follow the symbol on this path.
418191500Srwatson      State = State->remove<HStateMap>(CurItem.first);
41920407Swollman    }
420194602Srwatson    SymbolRef ErrorSym = CurItem.second.getErrorSym();
42120407Swollman    if (!ErrorSym)
42220407Swollman      continue;
42320407Swollman    ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
424108033Shsu    if (ErrorVal.isConstrainedTrue()) {
4251541Srgrimes      // Allocation succeeded.
42685740Sdes      if (CurItem.second.maybeAllocated())
4271541Srgrimes        State = State->set<HStateMap>(
4281541Srgrimes            CurItem.first, HandleState::getAllocated(State, CurItem.second));
4291541Srgrimes    } else if (ErrorVal.isConstrainedFalse()) {
4301541Srgrimes      // Allocation failed.
4311541Srgrimes      if (CurItem.second.maybeAllocated())
432151824Sglebius        State = State->remove<HStateMap>(CurItem.first);
433194760Srwatson    }
434194760Srwatson  }
435191285Srwatson  return State;
436194760Srwatson}
437194760Srwatson
438194951SrwatsonProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
439181803Sbz    ProgramStateRef State, const InvalidatedSymbols &Escaped,
440194951Srwatson    const CallEvent *Call, PointerEscapeKind Kind) const {
44187124Sbrian  const FunctionDecl *FuncDecl =
4421541Srgrimes      Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
4431541Srgrimes
4441541Srgrimes  llvm::DenseSet<SymbolRef> UnEscaped;
4451541Srgrimes  // Not all calls should escape our symbols.
4461541Srgrimes  if (FuncDecl &&
4471541Srgrimes      (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
4481541Srgrimes       Kind == PSK_EscapeOutParameters)) {
4491541Srgrimes    for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
450191500Srwatson      if (Arg >= FuncDecl->getNumParams())
451191500Srwatson        break;
452194760Srwatson      const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
453191500Srwatson      SymbolRef Handle =
4541541Srgrimes          getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State);
4551541Srgrimes      if (!Handle)
456191500Srwatson        continue;
457191500Srwatson      if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
458194760Srwatson          hasFuchsiaAttr<ReleaseHandleAttr>(PVD))
459194760Srwatson        UnEscaped.insert(Handle);
460191500Srwatson    }
4611541Srgrimes  }
4621541Srgrimes
4631541Srgrimes  // For out params, we have to deal with derived symbols. See
464194760Srwatson  // MacOSKeychainAPIChecker for details.
4651541Srgrimes  for (auto I : State->get<HStateMap>()) {
4661541Srgrimes    if (Escaped.count(I.first) && !UnEscaped.count(I.first))
467191500Srwatson      State = State->set<HStateMap>(I.first, HandleState::getEscaped());
468191500Srwatson    if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
469194760Srwatson      auto ParentSym = SD->getParentSymbol();
470191500Srwatson      if (Escaped.count(ParentSym))
4711541Srgrimes        State = State->set<HStateMap>(I.first, HandleState::getEscaped());
472194760Srwatson    }
4731541Srgrimes  }
4741541Srgrimes
475191500Srwatson  return State;
476191500Srwatson}
477194760Srwatson
478191500SrwatsonExplodedNode *
4791541SrgrimesFuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
480194760Srwatson                                  CheckerContext &C, ExplodedNode *Pred) const {
4811541Srgrimes  ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
4821541Srgrimes  for (SymbolRef LeakedHandle : LeakedHandles) {
4831541Srgrimes    reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
484194760Srwatson              "Potential leak of handle");
4851541Srgrimes  }
4861541Srgrimes  return ErrNode;
487191500Srwatson}
488191500Srwatson
489194760Srwatsonvoid FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
490191500Srwatson                                               const SourceRange &Range,
4911541Srgrimes                                               CheckerContext &C) const {
4921541Srgrimes  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
493184295Sbz  reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
494146883Siedowse            "Releasing a previously released handle");
495146883Siedowse}
496146883Siedowse
497146883Siedowsevoid FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
498194760Srwatson                                              const SourceRange &Range,
499146883Siedowse                                              CheckerContext &C) const {
5001541Srgrimes  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
5011541Srgrimes  reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
5021541Srgrimes            "Using a previously released handle");
5031541Srgrimes}
5041541Srgrimes
5051541Srgrimesvoid FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
5061541Srgrimes                                     CheckerContext &C,
5071541Srgrimes                                     const SourceRange *Range,
508194760Srwatson                                     const BugType &Type, StringRef Msg) const {
5091541Srgrimes  if (!ErrorNode)
5101541Srgrimes    return;
511191500Srwatson
512191500Srwatson  std::unique_ptr<PathSensitiveBugReport> R;
513194760Srwatson  if (Type.isSuppressOnSink()) {
514191500Srwatson    const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
5151541Srgrimes    if (AcquireNode) {
516194760Srwatson      PathDiagnosticLocation LocUsedForUniqueing =
5171541Srgrimes          PathDiagnosticLocation::createBegin(
5181541Srgrimes              AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
51987124Sbrian              AcquireNode->getLocationContext());
520228313Sglebius
52187124Sbrian      R = std::make_unique<PathSensitiveBugReport>(
52287124Sbrian          Type, Msg, ErrorNode, LocUsedForUniqueing,
523168032Sbms          AcquireNode->getLocationContext()->getDecl());
524189603Sbms    }
525189592Sbms  }
526189592Sbms  if (!R)
527189592Sbms    R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
528189592Sbms  if (Range)
529189592Sbms    R->addRange(*Range);
530126264Smlaier  R->markInteresting(Sym);
531168032Sbms  C.emitReport(std::move(R));
532194760Srwatson}
533194760Srwatson
5341541Srgrimesvoid ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
5351541Srgrimes  mgr.registerChecker<FuchsiaHandleChecker>();
536228062Sglebius}
537228062Sglebius
53885740Sdesbool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) {
539194760Srwatson  return true;
5401541Srgrimes}
5411541Srgrimes
5421541Srgrimesvoid FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
5431541Srgrimes                                      const char *NL, const char *Sep) const {
5441541Srgrimes
545227959Sglebius  HStateMapTy StateMap = State->get<HStateMap>();
546227791Sglebius
547227791Sglebius  if (!StateMap.isEmpty()) {
5481541Srgrimes    Out << Sep << "FuchsiaHandleChecker :" << NL;
549197210Sqingli    for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
550197210Sqingli         ++I) {
551197210Sqingli      I.getKey()->dumpToStream(Out);
552197210Sqingli      Out << " : ";
553197210Sqingli      I.getData().dump(Out);
554197210Sqingli      Out << NL;
555197210Sqingli    }
556197210Sqingli  }
557197210Sqingli}
558222438Sqingli