xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1480093f4SDimitry Andric //=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // This checker checks if the handle of Fuchsia is properly used according to
10480093f4SDimitry Andric // following rules.
11480093f4SDimitry Andric //   - If a handle is acquired, it should be released before execution
12480093f4SDimitry Andric //        ends.
13480093f4SDimitry Andric //   - If a handle is released, it should not be released again.
14480093f4SDimitry Andric //   - If a handle is released, it should not be used for other purposes
15480093f4SDimitry Andric //        such as I/O.
16480093f4SDimitry Andric //
17480093f4SDimitry Andric // In this checker, each tracked handle is associated with a state. When the
18480093f4SDimitry Andric // handle variable is passed to different function calls or syscalls, its state
19480093f4SDimitry Andric // changes. The state changes can be generally represented by following ASCII
20480093f4SDimitry Andric // Art:
21480093f4SDimitry Andric //
22480093f4SDimitry Andric //
23e8d8bef9SDimitry Andric //                                 +-------------+         +------------+
24480093f4SDimitry Andric //          acquire_func succeeded |             | Escape  |            |
25480093f4SDimitry Andric //               +----------------->  Allocated  +--------->  Escaped   <--+
26480093f4SDimitry Andric //               |                 |             |         |            |  |
27480093f4SDimitry Andric //               |                 +-----+------++         +------------+  |
28480093f4SDimitry Andric //               |                       |      |                          |
29e8d8bef9SDimitry Andric // acquire_func  |         release_func  |      +--+                       |
30e8d8bef9SDimitry Andric //    failed     |                       |         | handle  +--------+    |
31e8d8bef9SDimitry Andric // +---------+   |                       |         | dies    |        |    |
32e8d8bef9SDimitry Andric // |         |   |                  +----v-----+   +---------> Leaked |    |
33e8d8bef9SDimitry Andric // |         |   |                  |          |             |(REPORT)|    |
34e8d8bef9SDimitry Andric // |  +----------+--+               | Released | Escape      +--------+    |
35e8d8bef9SDimitry Andric // |  |             |               |          +---------------------------+
36e8d8bef9SDimitry Andric // +--> Not tracked |               +----+---+-+
37e8d8bef9SDimitry Andric //    |             |                    |   |        As argument by value
38e8d8bef9SDimitry Andric //    +----------+--+       release_func |   +------+ in function call
39e8d8bef9SDimitry Andric //               |                       |          | or by reference in
40e8d8bef9SDimitry Andric //               |                       |          | use_func call
41e8d8bef9SDimitry Andric //    unowned    |                  +----v-----+    |     +-----------+
42e8d8bef9SDimitry Andric //  acquire_func |                  | Double   |    +-----> Use after |
43e8d8bef9SDimitry Andric //   succeeded   |                  | released |          | released  |
44e8d8bef9SDimitry Andric //               |                  | (REPORT) |          | (REPORT)  |
45e8d8bef9SDimitry Andric //        +---------------+         +----------+          +-----------+
46e8d8bef9SDimitry Andric //        | Allocated     |
47e8d8bef9SDimitry Andric //        | Unowned       |  release_func
48e8d8bef9SDimitry Andric //        |               +---------+
49e8d8bef9SDimitry Andric //        +---------------+         |
50e8d8bef9SDimitry Andric //                                  |
51e8d8bef9SDimitry Andric //                            +-----v----------+
52e8d8bef9SDimitry Andric //                            | Release of     |
53e8d8bef9SDimitry Andric //                            | unowned handle |
54e8d8bef9SDimitry Andric //                            | (REPORT)       |
55e8d8bef9SDimitry Andric //                            +----------------+
56480093f4SDimitry Andric //
57480093f4SDimitry Andric // acquire_func represents the functions or syscalls that may acquire a handle.
58480093f4SDimitry Andric // release_func represents the functions or syscalls that may release a handle.
59480093f4SDimitry Andric // use_func represents the functions or syscall that requires an open handle.
60480093f4SDimitry Andric //
61480093f4SDimitry Andric // If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
62480093f4SDimitry Andric // is properly used. Otherwise a bug and will be reported.
63480093f4SDimitry Andric //
64480093f4SDimitry Andric // Note that, the analyzer does not always know for sure if a function failed
65480093f4SDimitry Andric // or succeeded. In those cases we use the state MaybeAllocated.
66e8d8bef9SDimitry Andric // Thus, the diagram above captures the intent, not implementation details.
67480093f4SDimitry Andric //
68480093f4SDimitry Andric // Due to the fact that the number of handle related syscalls in Fuchsia
69480093f4SDimitry Andric // is large, we adopt the annotation attributes to descript syscalls'
70480093f4SDimitry Andric // operations(acquire/release/use) on handles instead of hardcoding
71480093f4SDimitry Andric // everything in the checker.
72480093f4SDimitry Andric //
73480093f4SDimitry Andric // We use following annotation attributes for handle related syscalls or
74480093f4SDimitry Andric // functions:
75480093f4SDimitry Andric //  1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
76480093f4SDimitry Andric //  2. __attribute__((release_handle("Fuchsia"))) |handle will be released
77480093f4SDimitry Andric //  3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
78480093f4SDimitry Andric //     escaped state, it also needs to be open.
79480093f4SDimitry Andric //
80480093f4SDimitry Andric // For example, an annotated syscall:
81480093f4SDimitry Andric //   zx_status_t zx_channel_create(
82480093f4SDimitry Andric //   uint32_t options,
83480093f4SDimitry Andric //   zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
84480093f4SDimitry Andric //   zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
85480093f4SDimitry Andric // denotes a syscall which will acquire two handles and save them to 'out0' and
86480093f4SDimitry Andric // 'out1' when succeeded.
87480093f4SDimitry Andric //
88480093f4SDimitry Andric //===----------------------------------------------------------------------===//
89480093f4SDimitry Andric 
90480093f4SDimitry Andric #include "clang/AST/Attr.h"
91480093f4SDimitry Andric #include "clang/AST/Decl.h"
92480093f4SDimitry Andric #include "clang/AST/Type.h"
93480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
94480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
95480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
96480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
97480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
98480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
99480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
100480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
101480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
102480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
1035ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
104480093f4SDimitry Andric 
105480093f4SDimitry Andric using namespace clang;
106480093f4SDimitry Andric using namespace ento;
107480093f4SDimitry Andric 
108480093f4SDimitry Andric namespace {
109480093f4SDimitry Andric 
110480093f4SDimitry Andric static const StringRef HandleTypeName = "zx_handle_t";
111480093f4SDimitry Andric static const StringRef ErrorTypeName = "zx_status_t";
112480093f4SDimitry Andric 
113480093f4SDimitry Andric class HandleState {
114480093f4SDimitry Andric private:
115e8d8bef9SDimitry Andric   enum class Kind { MaybeAllocated, Allocated, Released, Escaped, Unowned } K;
116480093f4SDimitry Andric   SymbolRef ErrorSym;
117480093f4SDimitry Andric   HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
118480093f4SDimitry Andric 
119480093f4SDimitry Andric public:
120480093f4SDimitry Andric   bool operator==(const HandleState &Other) const {
121480093f4SDimitry Andric     return K == Other.K && ErrorSym == Other.ErrorSym;
122480093f4SDimitry Andric   }
123480093f4SDimitry Andric   bool isAllocated() const { return K == Kind::Allocated; }
124480093f4SDimitry Andric   bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
125480093f4SDimitry Andric   bool isReleased() const { return K == Kind::Released; }
126480093f4SDimitry Andric   bool isEscaped() const { return K == Kind::Escaped; }
127e8d8bef9SDimitry Andric   bool isUnowned() const { return K == Kind::Unowned; }
128480093f4SDimitry Andric 
129480093f4SDimitry Andric   static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
130480093f4SDimitry Andric     return HandleState(Kind::MaybeAllocated, ErrorSym);
131480093f4SDimitry Andric   }
132480093f4SDimitry Andric   static HandleState getAllocated(ProgramStateRef State, HandleState S) {
133480093f4SDimitry Andric     assert(S.maybeAllocated());
134480093f4SDimitry Andric     assert(State->getConstraintManager()
135480093f4SDimitry Andric                .isNull(State, S.getErrorSym())
136480093f4SDimitry Andric                .isConstrained());
137480093f4SDimitry Andric     return HandleState(Kind::Allocated, nullptr);
138480093f4SDimitry Andric   }
139480093f4SDimitry Andric   static HandleState getReleased() {
140480093f4SDimitry Andric     return HandleState(Kind::Released, nullptr);
141480093f4SDimitry Andric   }
142480093f4SDimitry Andric   static HandleState getEscaped() {
143480093f4SDimitry Andric     return HandleState(Kind::Escaped, nullptr);
144480093f4SDimitry Andric   }
145e8d8bef9SDimitry Andric   static HandleState getUnowned() {
146e8d8bef9SDimitry Andric     return HandleState(Kind::Unowned, nullptr);
147e8d8bef9SDimitry Andric   }
148480093f4SDimitry Andric 
149480093f4SDimitry Andric   SymbolRef getErrorSym() const { return ErrorSym; }
150480093f4SDimitry Andric 
151480093f4SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
152480093f4SDimitry Andric     ID.AddInteger(static_cast<int>(K));
153480093f4SDimitry Andric     ID.AddPointer(ErrorSym);
154480093f4SDimitry Andric   }
155480093f4SDimitry Andric 
156480093f4SDimitry Andric   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
157480093f4SDimitry Andric     switch (K) {
158480093f4SDimitry Andric #define CASE(ID)                                                               \
159480093f4SDimitry Andric   case ID:                                                                     \
160480093f4SDimitry Andric     OS << #ID;                                                                 \
161480093f4SDimitry Andric     break;
162480093f4SDimitry Andric       CASE(Kind::MaybeAllocated)
163480093f4SDimitry Andric       CASE(Kind::Allocated)
164480093f4SDimitry Andric       CASE(Kind::Released)
165480093f4SDimitry Andric       CASE(Kind::Escaped)
166e8d8bef9SDimitry Andric       CASE(Kind::Unowned)
167480093f4SDimitry Andric     }
1685ffd83dbSDimitry Andric     if (ErrorSym) {
1695ffd83dbSDimitry Andric       OS << " ErrorSym: ";
1705ffd83dbSDimitry Andric       ErrorSym->dumpToStream(OS);
1715ffd83dbSDimitry Andric     }
172480093f4SDimitry Andric   }
173480093f4SDimitry Andric 
174480093f4SDimitry Andric   LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
175480093f4SDimitry Andric };
176480093f4SDimitry Andric 
177480093f4SDimitry Andric template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
178480093f4SDimitry Andric   return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
179480093f4SDimitry Andric }
180480093f4SDimitry Andric 
181e8d8bef9SDimitry Andric template <typename Attr> static bool hasFuchsiaUnownedAttr(const Decl *D) {
182e8d8bef9SDimitry Andric   return D->hasAttr<Attr>() &&
183e8d8bef9SDimitry Andric          D->getAttr<Attr>()->getHandleType() == "FuchsiaUnowned";
184e8d8bef9SDimitry Andric }
185e8d8bef9SDimitry Andric 
186480093f4SDimitry Andric class FuchsiaHandleChecker
187480093f4SDimitry Andric     : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
188480093f4SDimitry Andric                      check::PointerEscape, eval::Assume> {
189480093f4SDimitry Andric   BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
190480093f4SDimitry Andric                       /*SuppressOnSink=*/true};
191480093f4SDimitry Andric   BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
192480093f4SDimitry Andric                                "Fuchsia Handle Error"};
193480093f4SDimitry Andric   BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
194480093f4SDimitry Andric                                  "Fuchsia Handle Error"};
195e8d8bef9SDimitry Andric   BugType ReleaseUnownedBugType{
196e8d8bef9SDimitry Andric       this, "Fuchsia handle release of unowned handle", "Fuchsia Handle Error"};
197480093f4SDimitry Andric 
198480093f4SDimitry Andric public:
199480093f4SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
200480093f4SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
201480093f4SDimitry Andric   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
202480093f4SDimitry Andric   ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
203480093f4SDimitry Andric                              bool Assumption) const;
204480093f4SDimitry Andric   ProgramStateRef checkPointerEscape(ProgramStateRef State,
205480093f4SDimitry Andric                                      const InvalidatedSymbols &Escaped,
206480093f4SDimitry Andric                                      const CallEvent *Call,
207480093f4SDimitry Andric                                      PointerEscapeKind Kind) const;
208480093f4SDimitry Andric 
209480093f4SDimitry Andric   ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
210480093f4SDimitry Andric                             CheckerContext &C, ExplodedNode *Pred) const;
211480093f4SDimitry Andric 
212480093f4SDimitry Andric   void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
213480093f4SDimitry Andric                            CheckerContext &C) const;
214480093f4SDimitry Andric 
215e8d8bef9SDimitry Andric   void reportUnownedRelease(SymbolRef HandleSym, const SourceRange &Range,
216e8d8bef9SDimitry Andric                             CheckerContext &C) const;
217e8d8bef9SDimitry Andric 
218480093f4SDimitry Andric   void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
219480093f4SDimitry Andric                           CheckerContext &C) const;
220480093f4SDimitry Andric 
221480093f4SDimitry Andric   void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
222480093f4SDimitry Andric                  const SourceRange *Range, const BugType &Type,
223480093f4SDimitry Andric                  StringRef Msg) const;
224480093f4SDimitry Andric 
225480093f4SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
226480093f4SDimitry Andric                   const char *Sep) const override;
227480093f4SDimitry Andric };
228480093f4SDimitry Andric } // end anonymous namespace
229480093f4SDimitry Andric 
230480093f4SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
231480093f4SDimitry Andric 
232480093f4SDimitry Andric static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
233480093f4SDimitry Andric                                           CheckerContext &Ctx) {
234480093f4SDimitry Andric   ProgramStateRef State = N->getState();
235480093f4SDimitry Andric   // When bug type is handle leak, exploded node N does not have state info for
236480093f4SDimitry Andric   // leaking handle. Get the predecessor of N instead.
237480093f4SDimitry Andric   if (!State->get<HStateMap>(Sym))
238480093f4SDimitry Andric     N = N->getFirstPred();
239480093f4SDimitry Andric 
240480093f4SDimitry Andric   const ExplodedNode *Pred = N;
241480093f4SDimitry Andric   while (N) {
242480093f4SDimitry Andric     State = N->getState();
243480093f4SDimitry Andric     if (!State->get<HStateMap>(Sym)) {
244480093f4SDimitry Andric       const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
245480093f4SDimitry Andric       if (HState && (HState->isAllocated() || HState->maybeAllocated()))
246480093f4SDimitry Andric         return N;
247480093f4SDimitry Andric     }
248480093f4SDimitry Andric     Pred = N;
249480093f4SDimitry Andric     N = N->getFirstPred();
250480093f4SDimitry Andric   }
251480093f4SDimitry Andric   return nullptr;
252480093f4SDimitry Andric }
253480093f4SDimitry Andric 
254e8d8bef9SDimitry Andric namespace {
255e8d8bef9SDimitry Andric class FuchsiaHandleSymbolVisitor final : public SymbolVisitor {
256e8d8bef9SDimitry Andric public:
257e8d8bef9SDimitry Andric   bool VisitSymbol(SymbolRef S) override {
258e8d8bef9SDimitry Andric     if (const auto *HandleType = S->getType()->getAs<TypedefType>())
259e8d8bef9SDimitry Andric       if (HandleType->getDecl()->getName() == HandleTypeName)
260e8d8bef9SDimitry Andric         Symbols.push_back(S);
261e8d8bef9SDimitry Andric     return true;
262e8d8bef9SDimitry Andric   }
263e8d8bef9SDimitry Andric 
264e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> GetSymbols() { return Symbols; }
265e8d8bef9SDimitry Andric 
266e8d8bef9SDimitry Andric private:
267e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> Symbols;
268e8d8bef9SDimitry Andric };
269e8d8bef9SDimitry Andric } // end anonymous namespace
270e8d8bef9SDimitry Andric 
271e8d8bef9SDimitry Andric /// Returns the symbols extracted from the argument or empty vector if it cannot
272e8d8bef9SDimitry Andric /// be found. It is unlikely to have over 1024 symbols in one argument.
273e8d8bef9SDimitry Andric static SmallVector<SymbolRef, 1024>
274e8d8bef9SDimitry Andric getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
275480093f4SDimitry Andric   int PtrToHandleLevel = 0;
276480093f4SDimitry Andric   while (QT->isAnyPointerType() || QT->isReferenceType()) {
277480093f4SDimitry Andric     ++PtrToHandleLevel;
278480093f4SDimitry Andric     QT = QT->getPointeeType();
279480093f4SDimitry Andric   }
280e8d8bef9SDimitry Andric   if (QT->isStructureType()) {
281e8d8bef9SDimitry Andric     // If we see a structure, see if there is any handle referenced by the
282e8d8bef9SDimitry Andric     // structure.
283*81ad6265SDimitry Andric     FuchsiaHandleSymbolVisitor Visitor;
284e8d8bef9SDimitry Andric     State->scanReachableSymbols(Arg, Visitor);
285e8d8bef9SDimitry Andric     return Visitor.GetSymbols();
286e8d8bef9SDimitry Andric   }
287480093f4SDimitry Andric   if (const auto *HandleType = QT->getAs<TypedefType>()) {
288480093f4SDimitry Andric     if (HandleType->getDecl()->getName() != HandleTypeName)
289e8d8bef9SDimitry Andric       return {};
290e8d8bef9SDimitry Andric     if (PtrToHandleLevel > 1)
291480093f4SDimitry Andric       // Not supported yet.
292e8d8bef9SDimitry Andric       return {};
293480093f4SDimitry Andric 
294480093f4SDimitry Andric     if (PtrToHandleLevel == 0) {
295e8d8bef9SDimitry Andric       SymbolRef Sym = Arg.getAsSymbol();
296e8d8bef9SDimitry Andric       if (Sym) {
297e8d8bef9SDimitry Andric         return {Sym};
298e8d8bef9SDimitry Andric       } else {
299e8d8bef9SDimitry Andric         return {};
300e8d8bef9SDimitry Andric       }
301480093f4SDimitry Andric     } else {
302480093f4SDimitry Andric       assert(PtrToHandleLevel == 1);
303e8d8bef9SDimitry Andric       if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
304e8d8bef9SDimitry Andric         SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
305e8d8bef9SDimitry Andric         if (Sym) {
306e8d8bef9SDimitry Andric           return {Sym};
307e8d8bef9SDimitry Andric         } else {
308e8d8bef9SDimitry Andric           return {};
309480093f4SDimitry Andric         }
310480093f4SDimitry Andric       }
311e8d8bef9SDimitry Andric     }
312e8d8bef9SDimitry Andric   }
313e8d8bef9SDimitry Andric   return {};
314480093f4SDimitry Andric }
315480093f4SDimitry Andric 
316480093f4SDimitry Andric void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
317480093f4SDimitry Andric                                         CheckerContext &C) const {
318480093f4SDimitry Andric   ProgramStateRef State = C.getState();
319480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
320480093f4SDimitry Andric   if (!FuncDecl) {
321480093f4SDimitry Andric     // Unknown call, escape by value handles. They are not covered by
322480093f4SDimitry Andric     // PointerEscape callback.
323480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
324480093f4SDimitry Andric       if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
325480093f4SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
326480093f4SDimitry Andric     }
327480093f4SDimitry Andric     C.addTransition(State);
328480093f4SDimitry Andric     return;
329480093f4SDimitry Andric   }
330480093f4SDimitry Andric 
331480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
332480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
333480093f4SDimitry Andric       break;
334480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
335e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
336e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
337480093f4SDimitry Andric 
338480093f4SDimitry Andric     // Handled in checkPostCall.
339480093f4SDimitry Andric     if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
340480093f4SDimitry Andric         hasFuchsiaAttr<AcquireHandleAttr>(PVD))
341480093f4SDimitry Andric       continue;
342480093f4SDimitry Andric 
343e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
344480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
345480093f4SDimitry Andric       if (!HState || HState->isEscaped())
346480093f4SDimitry Andric         continue;
347480093f4SDimitry Andric 
348e8d8bef9SDimitry Andric       if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
349e8d8bef9SDimitry Andric           PVD->getType()->isIntegerType()) {
350480093f4SDimitry Andric         if (HState->isReleased()) {
351480093f4SDimitry Andric           reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
352480093f4SDimitry Andric           return;
353480093f4SDimitry Andric         }
354480093f4SDimitry Andric       }
355480093f4SDimitry Andric     }
356480093f4SDimitry Andric   }
357480093f4SDimitry Andric   C.addTransition(State);
358480093f4SDimitry Andric }
359480093f4SDimitry Andric 
360480093f4SDimitry Andric void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
361480093f4SDimitry Andric                                          CheckerContext &C) const {
362480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
363480093f4SDimitry Andric   if (!FuncDecl)
364480093f4SDimitry Andric     return;
365480093f4SDimitry Andric 
366e8d8bef9SDimitry Andric   // If we analyzed the function body, then ignore the annotations.
367e8d8bef9SDimitry Andric   if (C.wasInlined)
368e8d8bef9SDimitry Andric     return;
369e8d8bef9SDimitry Andric 
370480093f4SDimitry Andric   ProgramStateRef State = C.getState();
371480093f4SDimitry Andric 
372480093f4SDimitry Andric   std::vector<std::function<std::string(BugReport & BR)>> Notes;
373480093f4SDimitry Andric   SymbolRef ResultSymbol = nullptr;
374480093f4SDimitry Andric   if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
375480093f4SDimitry Andric     if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
376480093f4SDimitry Andric       ResultSymbol = Call.getReturnValue().getAsSymbol();
377480093f4SDimitry Andric 
378480093f4SDimitry Andric   // Function returns an open handle.
379480093f4SDimitry Andric   if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
380480093f4SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3815ffd83dbSDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3825ffd83dbSDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
3835ffd83dbSDimitry Andric       if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
3845ffd83dbSDimitry Andric         std::string SBuf;
3855ffd83dbSDimitry Andric         llvm::raw_string_ostream OS(SBuf);
386e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
3875ffd83dbSDimitry Andric            << "' returns an open handle";
3880eae32dcSDimitry Andric         return SBuf;
3895ffd83dbSDimitry Andric       } else
3905ffd83dbSDimitry Andric         return "";
3915ffd83dbSDimitry Andric     });
392480093f4SDimitry Andric     State =
393480093f4SDimitry Andric         State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
394e8d8bef9SDimitry Andric   } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(FuncDecl)) {
395e8d8bef9SDimitry Andric     // Function returns an unowned handle
396e8d8bef9SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
397e8d8bef9SDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
398e8d8bef9SDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
399e8d8bef9SDimitry Andric       if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
400e8d8bef9SDimitry Andric         std::string SBuf;
401e8d8bef9SDimitry Andric         llvm::raw_string_ostream OS(SBuf);
402e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
403e8d8bef9SDimitry Andric            << "' returns an unowned handle";
4040eae32dcSDimitry Andric         return SBuf;
405e8d8bef9SDimitry Andric       } else
406e8d8bef9SDimitry Andric         return "";
407e8d8bef9SDimitry Andric     });
408e8d8bef9SDimitry Andric     State = State->set<HStateMap>(RetSym, HandleState::getUnowned());
409480093f4SDimitry Andric   }
410480093f4SDimitry Andric 
411480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
412480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
413480093f4SDimitry Andric       break;
414480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
4155ffd83dbSDimitry Andric     unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
416e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
417e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
418480093f4SDimitry Andric 
419e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
420480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
421480093f4SDimitry Andric       if (HState && HState->isEscaped())
422480093f4SDimitry Andric         continue;
423480093f4SDimitry Andric       if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
424480093f4SDimitry Andric         if (HState && HState->isReleased()) {
425480093f4SDimitry Andric           reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
426480093f4SDimitry Andric           return;
427e8d8bef9SDimitry Andric         } else if (HState && HState->isUnowned()) {
428e8d8bef9SDimitry Andric           reportUnownedRelease(Handle, Call.getArgSourceRange(Arg), C);
429e8d8bef9SDimitry Andric           return;
430480093f4SDimitry Andric         } else {
4315ffd83dbSDimitry Andric           Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
432480093f4SDimitry Andric             auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
433480093f4SDimitry Andric             if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4345ffd83dbSDimitry Andric               std::string SBuf;
4355ffd83dbSDimitry Andric               llvm::raw_string_ostream OS(SBuf);
4365ffd83dbSDimitry Andric               OS << "Handle released through " << ParamDiagIdx
4375ffd83dbSDimitry Andric                  << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4380eae32dcSDimitry Andric               return SBuf;
439480093f4SDimitry Andric             } else
440480093f4SDimitry Andric               return "";
441480093f4SDimitry Andric           });
442480093f4SDimitry Andric           State = State->set<HStateMap>(Handle, HandleState::getReleased());
443480093f4SDimitry Andric         }
444480093f4SDimitry Andric       } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
4455ffd83dbSDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
446480093f4SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
447480093f4SDimitry Andric           if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4485ffd83dbSDimitry Andric             std::string SBuf;
4495ffd83dbSDimitry Andric             llvm::raw_string_ostream OS(SBuf);
4505ffd83dbSDimitry Andric             OS << "Handle allocated through " << ParamDiagIdx
4515ffd83dbSDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4520eae32dcSDimitry Andric             return SBuf;
453480093f4SDimitry Andric           } else
454480093f4SDimitry Andric             return "";
455480093f4SDimitry Andric         });
456480093f4SDimitry Andric         State = State->set<HStateMap>(
457480093f4SDimitry Andric             Handle, HandleState::getMaybeAllocated(ResultSymbol));
458e8d8bef9SDimitry Andric       } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
459e8d8bef9SDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
460e8d8bef9SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
461e8d8bef9SDimitry Andric           if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
462e8d8bef9SDimitry Andric             std::string SBuf;
463e8d8bef9SDimitry Andric             llvm::raw_string_ostream OS(SBuf);
464e8d8bef9SDimitry Andric             OS << "Unowned handle allocated through " << ParamDiagIdx
465e8d8bef9SDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4660eae32dcSDimitry Andric             return SBuf;
467e8d8bef9SDimitry Andric           } else
468e8d8bef9SDimitry Andric             return "";
469e8d8bef9SDimitry Andric         });
470e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getUnowned());
471e8d8bef9SDimitry Andric       } else if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
472e8d8bef9SDimitry Andric                  PVD->getType()->isIntegerType()) {
473e8d8bef9SDimitry Andric         // Working around integer by-value escapes.
474e8d8bef9SDimitry Andric         // The by-value escape would not be captured in checkPointerEscape.
475e8d8bef9SDimitry Andric         // If the function was not analyzed (otherwise wasInlined should be
476e8d8bef9SDimitry Andric         // true) and there is no annotation on the handle, we assume the handle
477e8d8bef9SDimitry Andric         // is escaped.
478e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
479e8d8bef9SDimitry Andric       }
480480093f4SDimitry Andric     }
481480093f4SDimitry Andric   }
482480093f4SDimitry Andric   const NoteTag *T = nullptr;
483480093f4SDimitry Andric   if (!Notes.empty()) {
4845ffd83dbSDimitry Andric     T = C.getNoteTag([this, Notes{std::move(Notes)}](
4855ffd83dbSDimitry Andric                          PathSensitiveBugReport &BR) -> std::string {
486480093f4SDimitry Andric       if (&BR.getBugType() != &UseAfterReleaseBugType &&
487480093f4SDimitry Andric           &BR.getBugType() != &LeakBugType &&
488e8d8bef9SDimitry Andric           &BR.getBugType() != &DoubleReleaseBugType &&
489e8d8bef9SDimitry Andric           &BR.getBugType() != &ReleaseUnownedBugType)
490480093f4SDimitry Andric         return "";
491480093f4SDimitry Andric       for (auto &Note : Notes) {
492480093f4SDimitry Andric         std::string Text = Note(BR);
493480093f4SDimitry Andric         if (!Text.empty())
494480093f4SDimitry Andric           return Text;
495480093f4SDimitry Andric       }
496480093f4SDimitry Andric       return "";
497480093f4SDimitry Andric     });
498480093f4SDimitry Andric   }
499480093f4SDimitry Andric   C.addTransition(State, T);
500480093f4SDimitry Andric }
501480093f4SDimitry Andric 
502480093f4SDimitry Andric void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
503480093f4SDimitry Andric                                             CheckerContext &C) const {
504480093f4SDimitry Andric   ProgramStateRef State = C.getState();
505480093f4SDimitry Andric   SmallVector<SymbolRef, 2> LeakedSyms;
506480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
507480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
5085ffd83dbSDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
5095ffd83dbSDimitry Andric     // Keeping zombie handle symbols. In case the error symbol is dying later
5105ffd83dbSDimitry Andric     // than the handle symbol we might produce spurious leak warnings (in case
5115ffd83dbSDimitry Andric     // we find out later from the status code that the handle allocation failed
5125ffd83dbSDimitry Andric     // in the first place).
5135ffd83dbSDimitry Andric     if (!SymReaper.isDead(CurItem.first) ||
5145ffd83dbSDimitry Andric         (ErrorSym && !SymReaper.isDead(ErrorSym)))
515480093f4SDimitry Andric       continue;
516480093f4SDimitry Andric     if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
517480093f4SDimitry Andric       LeakedSyms.push_back(CurItem.first);
518480093f4SDimitry Andric     State = State->remove<HStateMap>(CurItem.first);
519480093f4SDimitry Andric   }
520480093f4SDimitry Andric 
521480093f4SDimitry Andric   ExplodedNode *N = C.getPredecessor();
522480093f4SDimitry Andric   if (!LeakedSyms.empty())
523480093f4SDimitry Andric     N = reportLeaks(LeakedSyms, C, N);
524480093f4SDimitry Andric 
525480093f4SDimitry Andric   C.addTransition(State, N);
526480093f4SDimitry Andric }
527480093f4SDimitry Andric 
528480093f4SDimitry Andric // Acquiring a handle is not always successful. In Fuchsia most functions
529480093f4SDimitry Andric // return a status code that determines the status of the handle.
530480093f4SDimitry Andric // When we split the path based on this status code we know that on one
531480093f4SDimitry Andric // path we do have the handle and on the other path the acquire failed.
532480093f4SDimitry Andric // This method helps avoiding false positive leak warnings on paths where
533480093f4SDimitry Andric // the function failed.
534480093f4SDimitry Andric // Moreover, when a handle is known to be zero (the invalid handle),
535480093f4SDimitry Andric // we no longer can follow the symbol on the path, becaue the constant
536480093f4SDimitry Andric // zero will be used instead of the symbol. We also do not need to release
537480093f4SDimitry Andric // an invalid handle, so we remove the corresponding symbol from the state.
538480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
539480093f4SDimitry Andric                                                  SVal Cond,
540480093f4SDimitry Andric                                                  bool Assumption) const {
541480093f4SDimitry Andric   // TODO: add notes about successes/fails for APIs.
542480093f4SDimitry Andric   ConstraintManager &Cmr = State->getConstraintManager();
543480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
544480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
545480093f4SDimitry Andric     ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
546480093f4SDimitry Andric     if (HandleVal.isConstrainedTrue()) {
547480093f4SDimitry Andric       // The handle is invalid. We can no longer follow the symbol on this path.
548480093f4SDimitry Andric       State = State->remove<HStateMap>(CurItem.first);
549480093f4SDimitry Andric     }
550480093f4SDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
551480093f4SDimitry Andric     if (!ErrorSym)
552480093f4SDimitry Andric       continue;
553480093f4SDimitry Andric     ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
554480093f4SDimitry Andric     if (ErrorVal.isConstrainedTrue()) {
555480093f4SDimitry Andric       // Allocation succeeded.
556480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
557480093f4SDimitry Andric         State = State->set<HStateMap>(
558480093f4SDimitry Andric             CurItem.first, HandleState::getAllocated(State, CurItem.second));
559480093f4SDimitry Andric     } else if (ErrorVal.isConstrainedFalse()) {
560480093f4SDimitry Andric       // Allocation failed.
561480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
562480093f4SDimitry Andric         State = State->remove<HStateMap>(CurItem.first);
563480093f4SDimitry Andric     }
564480093f4SDimitry Andric   }
565480093f4SDimitry Andric   return State;
566480093f4SDimitry Andric }
567480093f4SDimitry Andric 
568480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
569480093f4SDimitry Andric     ProgramStateRef State, const InvalidatedSymbols &Escaped,
570480093f4SDimitry Andric     const CallEvent *Call, PointerEscapeKind Kind) const {
571480093f4SDimitry Andric   const FunctionDecl *FuncDecl =
572480093f4SDimitry Andric       Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
573480093f4SDimitry Andric 
574480093f4SDimitry Andric   llvm::DenseSet<SymbolRef> UnEscaped;
575480093f4SDimitry Andric   // Not all calls should escape our symbols.
576480093f4SDimitry Andric   if (FuncDecl &&
577480093f4SDimitry Andric       (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
578480093f4SDimitry Andric        Kind == PSK_EscapeOutParameters)) {
579480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
580480093f4SDimitry Andric       if (Arg >= FuncDecl->getNumParams())
581480093f4SDimitry Andric         break;
582480093f4SDimitry Andric       const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
583e8d8bef9SDimitry Andric       SmallVector<SymbolRef, 1024> Handles =
584e8d8bef9SDimitry Andric           getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State);
585e8d8bef9SDimitry Andric       for (SymbolRef Handle : Handles) {
586480093f4SDimitry Andric         if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
587e8d8bef9SDimitry Andric             hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
588480093f4SDimitry Andric           UnEscaped.insert(Handle);
589480093f4SDimitry Andric         }
590480093f4SDimitry Andric       }
591e8d8bef9SDimitry Andric     }
592e8d8bef9SDimitry Andric   }
593480093f4SDimitry Andric 
594480093f4SDimitry Andric   // For out params, we have to deal with derived symbols. See
595480093f4SDimitry Andric   // MacOSKeychainAPIChecker for details.
596480093f4SDimitry Andric   for (auto I : State->get<HStateMap>()) {
597480093f4SDimitry Andric     if (Escaped.count(I.first) && !UnEscaped.count(I.first))
598480093f4SDimitry Andric       State = State->set<HStateMap>(I.first, HandleState::getEscaped());
599480093f4SDimitry Andric     if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
600480093f4SDimitry Andric       auto ParentSym = SD->getParentSymbol();
601480093f4SDimitry Andric       if (Escaped.count(ParentSym))
602480093f4SDimitry Andric         State = State->set<HStateMap>(I.first, HandleState::getEscaped());
603480093f4SDimitry Andric     }
604480093f4SDimitry Andric   }
605480093f4SDimitry Andric 
606480093f4SDimitry Andric   return State;
607480093f4SDimitry Andric }
608480093f4SDimitry Andric 
609480093f4SDimitry Andric ExplodedNode *
610480093f4SDimitry Andric FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
611480093f4SDimitry Andric                                   CheckerContext &C, ExplodedNode *Pred) const {
612480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
613480093f4SDimitry Andric   for (SymbolRef LeakedHandle : LeakedHandles) {
614480093f4SDimitry Andric     reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
615480093f4SDimitry Andric               "Potential leak of handle");
616480093f4SDimitry Andric   }
617480093f4SDimitry Andric   return ErrNode;
618480093f4SDimitry Andric }
619480093f4SDimitry Andric 
620480093f4SDimitry Andric void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
621480093f4SDimitry Andric                                                const SourceRange &Range,
622480093f4SDimitry Andric                                                CheckerContext &C) const {
623480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
624480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
625480093f4SDimitry Andric             "Releasing a previously released handle");
626480093f4SDimitry Andric }
627480093f4SDimitry Andric 
628e8d8bef9SDimitry Andric void FuchsiaHandleChecker::reportUnownedRelease(SymbolRef HandleSym,
629e8d8bef9SDimitry Andric                                                 const SourceRange &Range,
630e8d8bef9SDimitry Andric                                                 CheckerContext &C) const {
631e8d8bef9SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
632e8d8bef9SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, ReleaseUnownedBugType,
633e8d8bef9SDimitry Andric             "Releasing an unowned handle");
634e8d8bef9SDimitry Andric }
635e8d8bef9SDimitry Andric 
636480093f4SDimitry Andric void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
637480093f4SDimitry Andric                                               const SourceRange &Range,
638480093f4SDimitry Andric                                               CheckerContext &C) const {
639480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
640480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
641480093f4SDimitry Andric             "Using a previously released handle");
642480093f4SDimitry Andric }
643480093f4SDimitry Andric 
644480093f4SDimitry Andric void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
645480093f4SDimitry Andric                                      CheckerContext &C,
646480093f4SDimitry Andric                                      const SourceRange *Range,
647480093f4SDimitry Andric                                      const BugType &Type, StringRef Msg) const {
648480093f4SDimitry Andric   if (!ErrorNode)
649480093f4SDimitry Andric     return;
650480093f4SDimitry Andric 
651480093f4SDimitry Andric   std::unique_ptr<PathSensitiveBugReport> R;
652480093f4SDimitry Andric   if (Type.isSuppressOnSink()) {
653480093f4SDimitry Andric     const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
654480093f4SDimitry Andric     if (AcquireNode) {
655480093f4SDimitry Andric       PathDiagnosticLocation LocUsedForUniqueing =
656480093f4SDimitry Andric           PathDiagnosticLocation::createBegin(
657480093f4SDimitry Andric               AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
658480093f4SDimitry Andric               AcquireNode->getLocationContext());
659480093f4SDimitry Andric 
660480093f4SDimitry Andric       R = std::make_unique<PathSensitiveBugReport>(
661480093f4SDimitry Andric           Type, Msg, ErrorNode, LocUsedForUniqueing,
662480093f4SDimitry Andric           AcquireNode->getLocationContext()->getDecl());
663480093f4SDimitry Andric     }
664480093f4SDimitry Andric   }
665480093f4SDimitry Andric   if (!R)
666480093f4SDimitry Andric     R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
667480093f4SDimitry Andric   if (Range)
668480093f4SDimitry Andric     R->addRange(*Range);
669480093f4SDimitry Andric   R->markInteresting(Sym);
670480093f4SDimitry Andric   C.emitReport(std::move(R));
671480093f4SDimitry Andric }
672480093f4SDimitry Andric 
673480093f4SDimitry Andric void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
674480093f4SDimitry Andric   mgr.registerChecker<FuchsiaHandleChecker>();
675480093f4SDimitry Andric }
676480093f4SDimitry Andric 
6775ffd83dbSDimitry Andric bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
678480093f4SDimitry Andric   return true;
679480093f4SDimitry Andric }
680480093f4SDimitry Andric 
681480093f4SDimitry Andric void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
682480093f4SDimitry Andric                                       const char *NL, const char *Sep) const {
683480093f4SDimitry Andric 
684480093f4SDimitry Andric   HStateMapTy StateMap = State->get<HStateMap>();
685480093f4SDimitry Andric 
686480093f4SDimitry Andric   if (!StateMap.isEmpty()) {
687480093f4SDimitry Andric     Out << Sep << "FuchsiaHandleChecker :" << NL;
688480093f4SDimitry Andric     for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
689480093f4SDimitry Andric          ++I) {
690480093f4SDimitry Andric       I.getKey()->dumpToStream(Out);
691480093f4SDimitry Andric       Out << " : ";
692480093f4SDimitry Andric       I.getData().dump(Out);
693480093f4SDimitry Andric       Out << NL;
694480093f4SDimitry Andric     }
695480093f4SDimitry Andric   }
696480093f4SDimitry Andric }
697