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   FuchsiaHandleSymbolVisitor(ProgramStateRef State) : State(std::move(State)) {}
258e8d8bef9SDimitry Andric   ProgramStateRef getState() const { return State; }
259e8d8bef9SDimitry Andric 
260e8d8bef9SDimitry Andric   bool VisitSymbol(SymbolRef S) override {
261e8d8bef9SDimitry Andric     if (const auto *HandleType = S->getType()->getAs<TypedefType>())
262e8d8bef9SDimitry Andric       if (HandleType->getDecl()->getName() == HandleTypeName)
263e8d8bef9SDimitry Andric         Symbols.push_back(S);
264e8d8bef9SDimitry Andric     return true;
265e8d8bef9SDimitry Andric   }
266e8d8bef9SDimitry Andric 
267e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> GetSymbols() { return Symbols; }
268e8d8bef9SDimitry Andric 
269e8d8bef9SDimitry Andric private:
270e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> Symbols;
271e8d8bef9SDimitry Andric   ProgramStateRef State;
272e8d8bef9SDimitry Andric };
273e8d8bef9SDimitry Andric } // end anonymous namespace
274e8d8bef9SDimitry Andric 
275e8d8bef9SDimitry Andric /// Returns the symbols extracted from the argument or empty vector if it cannot
276e8d8bef9SDimitry Andric /// be found. It is unlikely to have over 1024 symbols in one argument.
277e8d8bef9SDimitry Andric static SmallVector<SymbolRef, 1024>
278e8d8bef9SDimitry Andric getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
279480093f4SDimitry Andric   int PtrToHandleLevel = 0;
280480093f4SDimitry Andric   while (QT->isAnyPointerType() || QT->isReferenceType()) {
281480093f4SDimitry Andric     ++PtrToHandleLevel;
282480093f4SDimitry Andric     QT = QT->getPointeeType();
283480093f4SDimitry Andric   }
284e8d8bef9SDimitry Andric   if (QT->isStructureType()) {
285e8d8bef9SDimitry Andric     // If we see a structure, see if there is any handle referenced by the
286e8d8bef9SDimitry Andric     // structure.
287e8d8bef9SDimitry Andric     FuchsiaHandleSymbolVisitor Visitor(State);
288e8d8bef9SDimitry Andric     State->scanReachableSymbols(Arg, Visitor);
289e8d8bef9SDimitry Andric     return Visitor.GetSymbols();
290e8d8bef9SDimitry Andric   }
291480093f4SDimitry Andric   if (const auto *HandleType = QT->getAs<TypedefType>()) {
292480093f4SDimitry Andric     if (HandleType->getDecl()->getName() != HandleTypeName)
293e8d8bef9SDimitry Andric       return {};
294e8d8bef9SDimitry Andric     if (PtrToHandleLevel > 1)
295480093f4SDimitry Andric       // Not supported yet.
296e8d8bef9SDimitry Andric       return {};
297480093f4SDimitry Andric 
298480093f4SDimitry Andric     if (PtrToHandleLevel == 0) {
299e8d8bef9SDimitry Andric       SymbolRef Sym = Arg.getAsSymbol();
300e8d8bef9SDimitry Andric       if (Sym) {
301e8d8bef9SDimitry Andric         return {Sym};
302e8d8bef9SDimitry Andric       } else {
303e8d8bef9SDimitry Andric         return {};
304e8d8bef9SDimitry Andric       }
305480093f4SDimitry Andric     } else {
306480093f4SDimitry Andric       assert(PtrToHandleLevel == 1);
307e8d8bef9SDimitry Andric       if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
308e8d8bef9SDimitry Andric         SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
309e8d8bef9SDimitry Andric         if (Sym) {
310e8d8bef9SDimitry Andric           return {Sym};
311e8d8bef9SDimitry Andric         } else {
312e8d8bef9SDimitry Andric           return {};
313480093f4SDimitry Andric         }
314480093f4SDimitry Andric       }
315e8d8bef9SDimitry Andric     }
316e8d8bef9SDimitry Andric   }
317e8d8bef9SDimitry Andric   return {};
318480093f4SDimitry Andric }
319480093f4SDimitry Andric 
320480093f4SDimitry Andric void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
321480093f4SDimitry Andric                                         CheckerContext &C) const {
322480093f4SDimitry Andric   ProgramStateRef State = C.getState();
323480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
324480093f4SDimitry Andric   if (!FuncDecl) {
325480093f4SDimitry Andric     // Unknown call, escape by value handles. They are not covered by
326480093f4SDimitry Andric     // PointerEscape callback.
327480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
328480093f4SDimitry Andric       if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
329480093f4SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
330480093f4SDimitry Andric     }
331480093f4SDimitry Andric     C.addTransition(State);
332480093f4SDimitry Andric     return;
333480093f4SDimitry Andric   }
334480093f4SDimitry Andric 
335480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
336480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
337480093f4SDimitry Andric       break;
338480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
339e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
340e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
341480093f4SDimitry Andric 
342480093f4SDimitry Andric     // Handled in checkPostCall.
343480093f4SDimitry Andric     if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
344480093f4SDimitry Andric         hasFuchsiaAttr<AcquireHandleAttr>(PVD))
345480093f4SDimitry Andric       continue;
346480093f4SDimitry Andric 
347e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
348480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
349480093f4SDimitry Andric       if (!HState || HState->isEscaped())
350480093f4SDimitry Andric         continue;
351480093f4SDimitry Andric 
352e8d8bef9SDimitry Andric       if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
353e8d8bef9SDimitry Andric           PVD->getType()->isIntegerType()) {
354480093f4SDimitry Andric         if (HState->isReleased()) {
355480093f4SDimitry Andric           reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
356480093f4SDimitry Andric           return;
357480093f4SDimitry Andric         }
358480093f4SDimitry Andric       }
359480093f4SDimitry Andric     }
360480093f4SDimitry Andric   }
361480093f4SDimitry Andric   C.addTransition(State);
362480093f4SDimitry Andric }
363480093f4SDimitry Andric 
364480093f4SDimitry Andric void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
365480093f4SDimitry Andric                                          CheckerContext &C) const {
366480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
367480093f4SDimitry Andric   if (!FuncDecl)
368480093f4SDimitry Andric     return;
369480093f4SDimitry Andric 
370e8d8bef9SDimitry Andric   // If we analyzed the function body, then ignore the annotations.
371e8d8bef9SDimitry Andric   if (C.wasInlined)
372e8d8bef9SDimitry Andric     return;
373e8d8bef9SDimitry Andric 
374480093f4SDimitry Andric   ProgramStateRef State = C.getState();
375480093f4SDimitry Andric 
376480093f4SDimitry Andric   std::vector<std::function<std::string(BugReport & BR)>> Notes;
377480093f4SDimitry Andric   SymbolRef ResultSymbol = nullptr;
378480093f4SDimitry Andric   if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
379480093f4SDimitry Andric     if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
380480093f4SDimitry Andric       ResultSymbol = Call.getReturnValue().getAsSymbol();
381480093f4SDimitry Andric 
382480093f4SDimitry Andric   // Function returns an open handle.
383480093f4SDimitry Andric   if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
384480093f4SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3855ffd83dbSDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3865ffd83dbSDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
3875ffd83dbSDimitry Andric       if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
3885ffd83dbSDimitry Andric         std::string SBuf;
3895ffd83dbSDimitry Andric         llvm::raw_string_ostream OS(SBuf);
390e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
3915ffd83dbSDimitry Andric            << "' returns an open handle";
392*0eae32dcSDimitry Andric         return SBuf;
3935ffd83dbSDimitry Andric       } else
3945ffd83dbSDimitry Andric         return "";
3955ffd83dbSDimitry Andric     });
396480093f4SDimitry Andric     State =
397480093f4SDimitry Andric         State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
398e8d8bef9SDimitry Andric   } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(FuncDecl)) {
399e8d8bef9SDimitry Andric     // Function returns an unowned handle
400e8d8bef9SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
401e8d8bef9SDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
402e8d8bef9SDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
403e8d8bef9SDimitry Andric       if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
404e8d8bef9SDimitry Andric         std::string SBuf;
405e8d8bef9SDimitry Andric         llvm::raw_string_ostream OS(SBuf);
406e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
407e8d8bef9SDimitry Andric            << "' returns an unowned handle";
408*0eae32dcSDimitry Andric         return SBuf;
409e8d8bef9SDimitry Andric       } else
410e8d8bef9SDimitry Andric         return "";
411e8d8bef9SDimitry Andric     });
412e8d8bef9SDimitry Andric     State = State->set<HStateMap>(RetSym, HandleState::getUnowned());
413480093f4SDimitry Andric   }
414480093f4SDimitry Andric 
415480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
416480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
417480093f4SDimitry Andric       break;
418480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
4195ffd83dbSDimitry Andric     unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
420e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
421e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
422480093f4SDimitry Andric 
423e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
424480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
425480093f4SDimitry Andric       if (HState && HState->isEscaped())
426480093f4SDimitry Andric         continue;
427480093f4SDimitry Andric       if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
428480093f4SDimitry Andric         if (HState && HState->isReleased()) {
429480093f4SDimitry Andric           reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
430480093f4SDimitry Andric           return;
431e8d8bef9SDimitry Andric         } else if (HState && HState->isUnowned()) {
432e8d8bef9SDimitry Andric           reportUnownedRelease(Handle, Call.getArgSourceRange(Arg), C);
433e8d8bef9SDimitry Andric           return;
434480093f4SDimitry Andric         } else {
4355ffd83dbSDimitry Andric           Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
436480093f4SDimitry Andric             auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
437480093f4SDimitry Andric             if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4385ffd83dbSDimitry Andric               std::string SBuf;
4395ffd83dbSDimitry Andric               llvm::raw_string_ostream OS(SBuf);
4405ffd83dbSDimitry Andric               OS << "Handle released through " << ParamDiagIdx
4415ffd83dbSDimitry Andric                  << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
442*0eae32dcSDimitry Andric               return SBuf;
443480093f4SDimitry Andric             } else
444480093f4SDimitry Andric               return "";
445480093f4SDimitry Andric           });
446480093f4SDimitry Andric           State = State->set<HStateMap>(Handle, HandleState::getReleased());
447480093f4SDimitry Andric         }
448480093f4SDimitry Andric       } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
4495ffd83dbSDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
450480093f4SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
451480093f4SDimitry Andric           if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4525ffd83dbSDimitry Andric             std::string SBuf;
4535ffd83dbSDimitry Andric             llvm::raw_string_ostream OS(SBuf);
4545ffd83dbSDimitry Andric             OS << "Handle allocated through " << ParamDiagIdx
4555ffd83dbSDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
456*0eae32dcSDimitry Andric             return SBuf;
457480093f4SDimitry Andric           } else
458480093f4SDimitry Andric             return "";
459480093f4SDimitry Andric         });
460480093f4SDimitry Andric         State = State->set<HStateMap>(
461480093f4SDimitry Andric             Handle, HandleState::getMaybeAllocated(ResultSymbol));
462e8d8bef9SDimitry Andric       } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
463e8d8bef9SDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
464e8d8bef9SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
465e8d8bef9SDimitry Andric           if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
466e8d8bef9SDimitry Andric             std::string SBuf;
467e8d8bef9SDimitry Andric             llvm::raw_string_ostream OS(SBuf);
468e8d8bef9SDimitry Andric             OS << "Unowned handle allocated through " << ParamDiagIdx
469e8d8bef9SDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
470*0eae32dcSDimitry Andric             return SBuf;
471e8d8bef9SDimitry Andric           } else
472e8d8bef9SDimitry Andric             return "";
473e8d8bef9SDimitry Andric         });
474e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getUnowned());
475e8d8bef9SDimitry Andric       } else if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
476e8d8bef9SDimitry Andric                  PVD->getType()->isIntegerType()) {
477e8d8bef9SDimitry Andric         // Working around integer by-value escapes.
478e8d8bef9SDimitry Andric         // The by-value escape would not be captured in checkPointerEscape.
479e8d8bef9SDimitry Andric         // If the function was not analyzed (otherwise wasInlined should be
480e8d8bef9SDimitry Andric         // true) and there is no annotation on the handle, we assume the handle
481e8d8bef9SDimitry Andric         // is escaped.
482e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
483e8d8bef9SDimitry Andric       }
484480093f4SDimitry Andric     }
485480093f4SDimitry Andric   }
486480093f4SDimitry Andric   const NoteTag *T = nullptr;
487480093f4SDimitry Andric   if (!Notes.empty()) {
4885ffd83dbSDimitry Andric     T = C.getNoteTag([this, Notes{std::move(Notes)}](
4895ffd83dbSDimitry Andric                          PathSensitiveBugReport &BR) -> std::string {
490480093f4SDimitry Andric       if (&BR.getBugType() != &UseAfterReleaseBugType &&
491480093f4SDimitry Andric           &BR.getBugType() != &LeakBugType &&
492e8d8bef9SDimitry Andric           &BR.getBugType() != &DoubleReleaseBugType &&
493e8d8bef9SDimitry Andric           &BR.getBugType() != &ReleaseUnownedBugType)
494480093f4SDimitry Andric         return "";
495480093f4SDimitry Andric       for (auto &Note : Notes) {
496480093f4SDimitry Andric         std::string Text = Note(BR);
497480093f4SDimitry Andric         if (!Text.empty())
498480093f4SDimitry Andric           return Text;
499480093f4SDimitry Andric       }
500480093f4SDimitry Andric       return "";
501480093f4SDimitry Andric     });
502480093f4SDimitry Andric   }
503480093f4SDimitry Andric   C.addTransition(State, T);
504480093f4SDimitry Andric }
505480093f4SDimitry Andric 
506480093f4SDimitry Andric void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
507480093f4SDimitry Andric                                             CheckerContext &C) const {
508480093f4SDimitry Andric   ProgramStateRef State = C.getState();
509480093f4SDimitry Andric   SmallVector<SymbolRef, 2> LeakedSyms;
510480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
511480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
5125ffd83dbSDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
5135ffd83dbSDimitry Andric     // Keeping zombie handle symbols. In case the error symbol is dying later
5145ffd83dbSDimitry Andric     // than the handle symbol we might produce spurious leak warnings (in case
5155ffd83dbSDimitry Andric     // we find out later from the status code that the handle allocation failed
5165ffd83dbSDimitry Andric     // in the first place).
5175ffd83dbSDimitry Andric     if (!SymReaper.isDead(CurItem.first) ||
5185ffd83dbSDimitry Andric         (ErrorSym && !SymReaper.isDead(ErrorSym)))
519480093f4SDimitry Andric       continue;
520480093f4SDimitry Andric     if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
521480093f4SDimitry Andric       LeakedSyms.push_back(CurItem.first);
522480093f4SDimitry Andric     State = State->remove<HStateMap>(CurItem.first);
523480093f4SDimitry Andric   }
524480093f4SDimitry Andric 
525480093f4SDimitry Andric   ExplodedNode *N = C.getPredecessor();
526480093f4SDimitry Andric   if (!LeakedSyms.empty())
527480093f4SDimitry Andric     N = reportLeaks(LeakedSyms, C, N);
528480093f4SDimitry Andric 
529480093f4SDimitry Andric   C.addTransition(State, N);
530480093f4SDimitry Andric }
531480093f4SDimitry Andric 
532480093f4SDimitry Andric // Acquiring a handle is not always successful. In Fuchsia most functions
533480093f4SDimitry Andric // return a status code that determines the status of the handle.
534480093f4SDimitry Andric // When we split the path based on this status code we know that on one
535480093f4SDimitry Andric // path we do have the handle and on the other path the acquire failed.
536480093f4SDimitry Andric // This method helps avoiding false positive leak warnings on paths where
537480093f4SDimitry Andric // the function failed.
538480093f4SDimitry Andric // Moreover, when a handle is known to be zero (the invalid handle),
539480093f4SDimitry Andric // we no longer can follow the symbol on the path, becaue the constant
540480093f4SDimitry Andric // zero will be used instead of the symbol. We also do not need to release
541480093f4SDimitry Andric // an invalid handle, so we remove the corresponding symbol from the state.
542480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
543480093f4SDimitry Andric                                                  SVal Cond,
544480093f4SDimitry Andric                                                  bool Assumption) const {
545480093f4SDimitry Andric   // TODO: add notes about successes/fails for APIs.
546480093f4SDimitry Andric   ConstraintManager &Cmr = State->getConstraintManager();
547480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
548480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
549480093f4SDimitry Andric     ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
550480093f4SDimitry Andric     if (HandleVal.isConstrainedTrue()) {
551480093f4SDimitry Andric       // The handle is invalid. We can no longer follow the symbol on this path.
552480093f4SDimitry Andric       State = State->remove<HStateMap>(CurItem.first);
553480093f4SDimitry Andric     }
554480093f4SDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
555480093f4SDimitry Andric     if (!ErrorSym)
556480093f4SDimitry Andric       continue;
557480093f4SDimitry Andric     ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
558480093f4SDimitry Andric     if (ErrorVal.isConstrainedTrue()) {
559480093f4SDimitry Andric       // Allocation succeeded.
560480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
561480093f4SDimitry Andric         State = State->set<HStateMap>(
562480093f4SDimitry Andric             CurItem.first, HandleState::getAllocated(State, CurItem.second));
563480093f4SDimitry Andric     } else if (ErrorVal.isConstrainedFalse()) {
564480093f4SDimitry Andric       // Allocation failed.
565480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
566480093f4SDimitry Andric         State = State->remove<HStateMap>(CurItem.first);
567480093f4SDimitry Andric     }
568480093f4SDimitry Andric   }
569480093f4SDimitry Andric   return State;
570480093f4SDimitry Andric }
571480093f4SDimitry Andric 
572480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
573480093f4SDimitry Andric     ProgramStateRef State, const InvalidatedSymbols &Escaped,
574480093f4SDimitry Andric     const CallEvent *Call, PointerEscapeKind Kind) const {
575480093f4SDimitry Andric   const FunctionDecl *FuncDecl =
576480093f4SDimitry Andric       Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
577480093f4SDimitry Andric 
578480093f4SDimitry Andric   llvm::DenseSet<SymbolRef> UnEscaped;
579480093f4SDimitry Andric   // Not all calls should escape our symbols.
580480093f4SDimitry Andric   if (FuncDecl &&
581480093f4SDimitry Andric       (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
582480093f4SDimitry Andric        Kind == PSK_EscapeOutParameters)) {
583480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
584480093f4SDimitry Andric       if (Arg >= FuncDecl->getNumParams())
585480093f4SDimitry Andric         break;
586480093f4SDimitry Andric       const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
587e8d8bef9SDimitry Andric       SmallVector<SymbolRef, 1024> Handles =
588e8d8bef9SDimitry Andric           getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State);
589e8d8bef9SDimitry Andric       for (SymbolRef Handle : Handles) {
590480093f4SDimitry Andric         if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
591e8d8bef9SDimitry Andric             hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
592480093f4SDimitry Andric           UnEscaped.insert(Handle);
593480093f4SDimitry Andric         }
594480093f4SDimitry Andric       }
595e8d8bef9SDimitry Andric     }
596e8d8bef9SDimitry Andric   }
597480093f4SDimitry Andric 
598480093f4SDimitry Andric   // For out params, we have to deal with derived symbols. See
599480093f4SDimitry Andric   // MacOSKeychainAPIChecker for details.
600480093f4SDimitry Andric   for (auto I : State->get<HStateMap>()) {
601480093f4SDimitry Andric     if (Escaped.count(I.first) && !UnEscaped.count(I.first))
602480093f4SDimitry Andric       State = State->set<HStateMap>(I.first, HandleState::getEscaped());
603480093f4SDimitry Andric     if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
604480093f4SDimitry Andric       auto ParentSym = SD->getParentSymbol();
605480093f4SDimitry Andric       if (Escaped.count(ParentSym))
606480093f4SDimitry Andric         State = State->set<HStateMap>(I.first, HandleState::getEscaped());
607480093f4SDimitry Andric     }
608480093f4SDimitry Andric   }
609480093f4SDimitry Andric 
610480093f4SDimitry Andric   return State;
611480093f4SDimitry Andric }
612480093f4SDimitry Andric 
613480093f4SDimitry Andric ExplodedNode *
614480093f4SDimitry Andric FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
615480093f4SDimitry Andric                                   CheckerContext &C, ExplodedNode *Pred) const {
616480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
617480093f4SDimitry Andric   for (SymbolRef LeakedHandle : LeakedHandles) {
618480093f4SDimitry Andric     reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
619480093f4SDimitry Andric               "Potential leak of handle");
620480093f4SDimitry Andric   }
621480093f4SDimitry Andric   return ErrNode;
622480093f4SDimitry Andric }
623480093f4SDimitry Andric 
624480093f4SDimitry Andric void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
625480093f4SDimitry Andric                                                const SourceRange &Range,
626480093f4SDimitry Andric                                                CheckerContext &C) const {
627480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
628480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
629480093f4SDimitry Andric             "Releasing a previously released handle");
630480093f4SDimitry Andric }
631480093f4SDimitry Andric 
632e8d8bef9SDimitry Andric void FuchsiaHandleChecker::reportUnownedRelease(SymbolRef HandleSym,
633e8d8bef9SDimitry Andric                                                 const SourceRange &Range,
634e8d8bef9SDimitry Andric                                                 CheckerContext &C) const {
635e8d8bef9SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
636e8d8bef9SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, ReleaseUnownedBugType,
637e8d8bef9SDimitry Andric             "Releasing an unowned handle");
638e8d8bef9SDimitry Andric }
639e8d8bef9SDimitry Andric 
640480093f4SDimitry Andric void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
641480093f4SDimitry Andric                                               const SourceRange &Range,
642480093f4SDimitry Andric                                               CheckerContext &C) const {
643480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
644480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
645480093f4SDimitry Andric             "Using a previously released handle");
646480093f4SDimitry Andric }
647480093f4SDimitry Andric 
648480093f4SDimitry Andric void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
649480093f4SDimitry Andric                                      CheckerContext &C,
650480093f4SDimitry Andric                                      const SourceRange *Range,
651480093f4SDimitry Andric                                      const BugType &Type, StringRef Msg) const {
652480093f4SDimitry Andric   if (!ErrorNode)
653480093f4SDimitry Andric     return;
654480093f4SDimitry Andric 
655480093f4SDimitry Andric   std::unique_ptr<PathSensitiveBugReport> R;
656480093f4SDimitry Andric   if (Type.isSuppressOnSink()) {
657480093f4SDimitry Andric     const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
658480093f4SDimitry Andric     if (AcquireNode) {
659480093f4SDimitry Andric       PathDiagnosticLocation LocUsedForUniqueing =
660480093f4SDimitry Andric           PathDiagnosticLocation::createBegin(
661480093f4SDimitry Andric               AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
662480093f4SDimitry Andric               AcquireNode->getLocationContext());
663480093f4SDimitry Andric 
664480093f4SDimitry Andric       R = std::make_unique<PathSensitiveBugReport>(
665480093f4SDimitry Andric           Type, Msg, ErrorNode, LocUsedForUniqueing,
666480093f4SDimitry Andric           AcquireNode->getLocationContext()->getDecl());
667480093f4SDimitry Andric     }
668480093f4SDimitry Andric   }
669480093f4SDimitry Andric   if (!R)
670480093f4SDimitry Andric     R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
671480093f4SDimitry Andric   if (Range)
672480093f4SDimitry Andric     R->addRange(*Range);
673480093f4SDimitry Andric   R->markInteresting(Sym);
674480093f4SDimitry Andric   C.emitReport(std::move(R));
675480093f4SDimitry Andric }
676480093f4SDimitry Andric 
677480093f4SDimitry Andric void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
678480093f4SDimitry Andric   mgr.registerChecker<FuchsiaHandleChecker>();
679480093f4SDimitry Andric }
680480093f4SDimitry Andric 
6815ffd83dbSDimitry Andric bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
682480093f4SDimitry Andric   return true;
683480093f4SDimitry Andric }
684480093f4SDimitry Andric 
685480093f4SDimitry Andric void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
686480093f4SDimitry Andric                                       const char *NL, const char *Sep) const {
687480093f4SDimitry Andric 
688480093f4SDimitry Andric   HStateMapTy StateMap = State->get<HStateMap>();
689480093f4SDimitry Andric 
690480093f4SDimitry Andric   if (!StateMap.isEmpty()) {
691480093f4SDimitry Andric     Out << Sep << "FuchsiaHandleChecker :" << NL;
692480093f4SDimitry Andric     for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
693480093f4SDimitry Andric          ++I) {
694480093f4SDimitry Andric       I.getKey()->dumpToStream(Out);
695480093f4SDimitry Andric       Out << " : ";
696480093f4SDimitry Andric       I.getData().dump(Out);
697480093f4SDimitry Andric       Out << NL;
698480093f4SDimitry Andric     }
699480093f4SDimitry Andric   }
700480093f4SDimitry Andric }
701