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"
104bdd1243dSDimitry Andric #include <optional>
105480093f4SDimitry Andric 
106480093f4SDimitry Andric using namespace clang;
107480093f4SDimitry Andric using namespace ento;
108480093f4SDimitry Andric 
109480093f4SDimitry Andric namespace {
110480093f4SDimitry Andric 
111480093f4SDimitry Andric static const StringRef HandleTypeName = "zx_handle_t";
112480093f4SDimitry Andric static const StringRef ErrorTypeName = "zx_status_t";
113480093f4SDimitry Andric 
114480093f4SDimitry Andric class HandleState {
115480093f4SDimitry Andric private:
116e8d8bef9SDimitry Andric   enum class Kind { MaybeAllocated, Allocated, Released, Escaped, Unowned } K;
117480093f4SDimitry Andric   SymbolRef ErrorSym;
HandleState(Kind K,SymbolRef ErrorSym)118480093f4SDimitry Andric   HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
119480093f4SDimitry Andric 
120480093f4SDimitry Andric public:
operator ==(const HandleState & Other) const121480093f4SDimitry Andric   bool operator==(const HandleState &Other) const {
122480093f4SDimitry Andric     return K == Other.K && ErrorSym == Other.ErrorSym;
123480093f4SDimitry Andric   }
isAllocated() const124480093f4SDimitry Andric   bool isAllocated() const { return K == Kind::Allocated; }
maybeAllocated() const125480093f4SDimitry Andric   bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
isReleased() const126480093f4SDimitry Andric   bool isReleased() const { return K == Kind::Released; }
isEscaped() const127480093f4SDimitry Andric   bool isEscaped() const { return K == Kind::Escaped; }
isUnowned() const128e8d8bef9SDimitry Andric   bool isUnowned() const { return K == Kind::Unowned; }
129480093f4SDimitry Andric 
getMaybeAllocated(SymbolRef ErrorSym)130480093f4SDimitry Andric   static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
131480093f4SDimitry Andric     return HandleState(Kind::MaybeAllocated, ErrorSym);
132480093f4SDimitry Andric   }
getAllocated(ProgramStateRef State,HandleState S)133480093f4SDimitry Andric   static HandleState getAllocated(ProgramStateRef State, HandleState S) {
134480093f4SDimitry Andric     assert(S.maybeAllocated());
135480093f4SDimitry Andric     assert(State->getConstraintManager()
136480093f4SDimitry Andric                .isNull(State, S.getErrorSym())
137480093f4SDimitry Andric                .isConstrained());
138480093f4SDimitry Andric     return HandleState(Kind::Allocated, nullptr);
139480093f4SDimitry Andric   }
getReleased()140480093f4SDimitry Andric   static HandleState getReleased() {
141480093f4SDimitry Andric     return HandleState(Kind::Released, nullptr);
142480093f4SDimitry Andric   }
getEscaped()143480093f4SDimitry Andric   static HandleState getEscaped() {
144480093f4SDimitry Andric     return HandleState(Kind::Escaped, nullptr);
145480093f4SDimitry Andric   }
getUnowned()146e8d8bef9SDimitry Andric   static HandleState getUnowned() {
147e8d8bef9SDimitry Andric     return HandleState(Kind::Unowned, nullptr);
148e8d8bef9SDimitry Andric   }
149480093f4SDimitry Andric 
getErrorSym() const150480093f4SDimitry Andric   SymbolRef getErrorSym() const { return ErrorSym; }
151480093f4SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const152480093f4SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
153480093f4SDimitry Andric     ID.AddInteger(static_cast<int>(K));
154480093f4SDimitry Andric     ID.AddPointer(ErrorSym);
155480093f4SDimitry Andric   }
156480093f4SDimitry Andric 
dump(raw_ostream & OS) const157480093f4SDimitry Andric   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
158480093f4SDimitry Andric     switch (K) {
159480093f4SDimitry Andric #define CASE(ID)                                                               \
160480093f4SDimitry Andric   case ID:                                                                     \
161480093f4SDimitry Andric     OS << #ID;                                                                 \
162480093f4SDimitry Andric     break;
163480093f4SDimitry Andric       CASE(Kind::MaybeAllocated)
164480093f4SDimitry Andric       CASE(Kind::Allocated)
165480093f4SDimitry Andric       CASE(Kind::Released)
166480093f4SDimitry Andric       CASE(Kind::Escaped)
167e8d8bef9SDimitry Andric       CASE(Kind::Unowned)
168480093f4SDimitry Andric     }
1695ffd83dbSDimitry Andric     if (ErrorSym) {
1705ffd83dbSDimitry Andric       OS << " ErrorSym: ";
1715ffd83dbSDimitry Andric       ErrorSym->dumpToStream(OS);
1725ffd83dbSDimitry Andric     }
173480093f4SDimitry Andric   }
174480093f4SDimitry Andric 
dump() const175480093f4SDimitry Andric   LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
176480093f4SDimitry Andric };
177480093f4SDimitry Andric 
hasFuchsiaAttr(const Decl * D)178480093f4SDimitry Andric template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
179480093f4SDimitry Andric   return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
180480093f4SDimitry Andric }
181480093f4SDimitry Andric 
hasFuchsiaUnownedAttr(const Decl * D)182e8d8bef9SDimitry Andric template <typename Attr> static bool hasFuchsiaUnownedAttr(const Decl *D) {
183e8d8bef9SDimitry Andric   return D->hasAttr<Attr>() &&
184e8d8bef9SDimitry Andric          D->getAttr<Attr>()->getHandleType() == "FuchsiaUnowned";
185e8d8bef9SDimitry Andric }
186e8d8bef9SDimitry Andric 
187480093f4SDimitry Andric class FuchsiaHandleChecker
188480093f4SDimitry Andric     : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
189480093f4SDimitry Andric                      check::PointerEscape, eval::Assume> {
190480093f4SDimitry Andric   BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
191480093f4SDimitry Andric                       /*SuppressOnSink=*/true};
192480093f4SDimitry Andric   BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
193480093f4SDimitry Andric                                "Fuchsia Handle Error"};
194480093f4SDimitry Andric   BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
195480093f4SDimitry Andric                                  "Fuchsia Handle Error"};
196e8d8bef9SDimitry Andric   BugType ReleaseUnownedBugType{
197e8d8bef9SDimitry Andric       this, "Fuchsia handle release of unowned handle", "Fuchsia Handle Error"};
198480093f4SDimitry Andric 
199480093f4SDimitry Andric public:
200480093f4SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
201480093f4SDimitry Andric   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
202480093f4SDimitry Andric   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
203480093f4SDimitry Andric   ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
204480093f4SDimitry Andric                              bool Assumption) const;
205480093f4SDimitry Andric   ProgramStateRef checkPointerEscape(ProgramStateRef State,
206480093f4SDimitry Andric                                      const InvalidatedSymbols &Escaped,
207480093f4SDimitry Andric                                      const CallEvent *Call,
208480093f4SDimitry Andric                                      PointerEscapeKind Kind) const;
209480093f4SDimitry Andric 
210480093f4SDimitry Andric   ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
211480093f4SDimitry Andric                             CheckerContext &C, ExplodedNode *Pred) const;
212480093f4SDimitry Andric 
213480093f4SDimitry Andric   void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
214480093f4SDimitry Andric                            CheckerContext &C) const;
215480093f4SDimitry Andric 
216e8d8bef9SDimitry Andric   void reportUnownedRelease(SymbolRef HandleSym, const SourceRange &Range,
217e8d8bef9SDimitry Andric                             CheckerContext &C) const;
218e8d8bef9SDimitry Andric 
219480093f4SDimitry Andric   void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
220480093f4SDimitry Andric                           CheckerContext &C) const;
221480093f4SDimitry Andric 
222480093f4SDimitry Andric   void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
223480093f4SDimitry Andric                  const SourceRange *Range, const BugType &Type,
224480093f4SDimitry Andric                  StringRef Msg) const;
225480093f4SDimitry Andric 
226480093f4SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
227480093f4SDimitry Andric                   const char *Sep) const override;
228480093f4SDimitry Andric };
229480093f4SDimitry Andric } // end anonymous namespace
230480093f4SDimitry Andric 
REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap,SymbolRef,HandleState) const231480093f4SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
232480093f4SDimitry Andric 
233480093f4SDimitry Andric static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
234480093f4SDimitry Andric                                           CheckerContext &Ctx) {
235480093f4SDimitry Andric   ProgramStateRef State = N->getState();
236480093f4SDimitry Andric   // When bug type is handle leak, exploded node N does not have state info for
237480093f4SDimitry Andric   // leaking handle. Get the predecessor of N instead.
238480093f4SDimitry Andric   if (!State->get<HStateMap>(Sym))
239480093f4SDimitry Andric     N = N->getFirstPred();
240480093f4SDimitry Andric 
241480093f4SDimitry Andric   const ExplodedNode *Pred = N;
242480093f4SDimitry Andric   while (N) {
243480093f4SDimitry Andric     State = N->getState();
244480093f4SDimitry Andric     if (!State->get<HStateMap>(Sym)) {
245480093f4SDimitry Andric       const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
246480093f4SDimitry Andric       if (HState && (HState->isAllocated() || HState->maybeAllocated()))
247480093f4SDimitry Andric         return N;
248480093f4SDimitry Andric     }
249480093f4SDimitry Andric     Pred = N;
250480093f4SDimitry Andric     N = N->getFirstPred();
251480093f4SDimitry Andric   }
252480093f4SDimitry Andric   return nullptr;
253480093f4SDimitry Andric }
254480093f4SDimitry Andric 
255e8d8bef9SDimitry Andric namespace {
256e8d8bef9SDimitry Andric class FuchsiaHandleSymbolVisitor final : public SymbolVisitor {
257e8d8bef9SDimitry Andric public:
VisitSymbol(SymbolRef S)258e8d8bef9SDimitry Andric   bool VisitSymbol(SymbolRef S) override {
259e8d8bef9SDimitry Andric     if (const auto *HandleType = S->getType()->getAs<TypedefType>())
260e8d8bef9SDimitry Andric       if (HandleType->getDecl()->getName() == HandleTypeName)
261e8d8bef9SDimitry Andric         Symbols.push_back(S);
262e8d8bef9SDimitry Andric     return true;
263e8d8bef9SDimitry Andric   }
264e8d8bef9SDimitry Andric 
GetSymbols()265e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> GetSymbols() { return Symbols; }
266e8d8bef9SDimitry Andric 
267e8d8bef9SDimitry Andric private:
268e8d8bef9SDimitry Andric   SmallVector<SymbolRef, 1024> Symbols;
269e8d8bef9SDimitry Andric };
270e8d8bef9SDimitry Andric } // end anonymous namespace
271e8d8bef9SDimitry Andric 
272e8d8bef9SDimitry Andric /// Returns the symbols extracted from the argument or empty vector if it cannot
273e8d8bef9SDimitry Andric /// be found. It is unlikely to have over 1024 symbols in one argument.
274e8d8bef9SDimitry Andric static SmallVector<SymbolRef, 1024>
getFuchsiaHandleSymbols(QualType QT,SVal Arg,ProgramStateRef State)275e8d8bef9SDimitry Andric getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
276480093f4SDimitry Andric   int PtrToHandleLevel = 0;
277480093f4SDimitry Andric   while (QT->isAnyPointerType() || QT->isReferenceType()) {
278480093f4SDimitry Andric     ++PtrToHandleLevel;
279480093f4SDimitry Andric     QT = QT->getPointeeType();
280480093f4SDimitry Andric   }
281e8d8bef9SDimitry Andric   if (QT->isStructureType()) {
282e8d8bef9SDimitry Andric     // If we see a structure, see if there is any handle referenced by the
283e8d8bef9SDimitry Andric     // structure.
28481ad6265SDimitry Andric     FuchsiaHandleSymbolVisitor Visitor;
285e8d8bef9SDimitry Andric     State->scanReachableSymbols(Arg, Visitor);
286e8d8bef9SDimitry Andric     return Visitor.GetSymbols();
287e8d8bef9SDimitry Andric   }
288480093f4SDimitry Andric   if (const auto *HandleType = QT->getAs<TypedefType>()) {
289480093f4SDimitry Andric     if (HandleType->getDecl()->getName() != HandleTypeName)
290e8d8bef9SDimitry Andric       return {};
291e8d8bef9SDimitry Andric     if (PtrToHandleLevel > 1)
292480093f4SDimitry Andric       // Not supported yet.
293e8d8bef9SDimitry Andric       return {};
294480093f4SDimitry Andric 
295480093f4SDimitry Andric     if (PtrToHandleLevel == 0) {
296e8d8bef9SDimitry Andric       SymbolRef Sym = Arg.getAsSymbol();
297e8d8bef9SDimitry Andric       if (Sym) {
298e8d8bef9SDimitry Andric         return {Sym};
299e8d8bef9SDimitry Andric       } else {
300e8d8bef9SDimitry Andric         return {};
301e8d8bef9SDimitry Andric       }
302480093f4SDimitry Andric     } else {
303480093f4SDimitry Andric       assert(PtrToHandleLevel == 1);
304bdd1243dSDimitry Andric       if (std::optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
305e8d8bef9SDimitry Andric         SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
306e8d8bef9SDimitry Andric         if (Sym) {
307e8d8bef9SDimitry Andric           return {Sym};
308e8d8bef9SDimitry Andric         } else {
309e8d8bef9SDimitry Andric           return {};
310480093f4SDimitry Andric         }
311480093f4SDimitry Andric       }
312e8d8bef9SDimitry Andric     }
313e8d8bef9SDimitry Andric   }
314e8d8bef9SDimitry Andric   return {};
315480093f4SDimitry Andric }
316480093f4SDimitry Andric 
checkPreCall(const CallEvent & Call,CheckerContext & C) const317480093f4SDimitry Andric void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
318480093f4SDimitry Andric                                         CheckerContext &C) const {
319480093f4SDimitry Andric   ProgramStateRef State = C.getState();
320480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
321480093f4SDimitry Andric   if (!FuncDecl) {
322480093f4SDimitry Andric     // Unknown call, escape by value handles. They are not covered by
323480093f4SDimitry Andric     // PointerEscape callback.
324480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
325480093f4SDimitry Andric       if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
326480093f4SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
327480093f4SDimitry Andric     }
328480093f4SDimitry Andric     C.addTransition(State);
329480093f4SDimitry Andric     return;
330480093f4SDimitry Andric   }
331480093f4SDimitry Andric 
332480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
333480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
334480093f4SDimitry Andric       break;
335480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
336e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
337e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
338480093f4SDimitry Andric 
339480093f4SDimitry Andric     // Handled in checkPostCall.
340480093f4SDimitry Andric     if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
341480093f4SDimitry Andric         hasFuchsiaAttr<AcquireHandleAttr>(PVD))
342480093f4SDimitry Andric       continue;
343480093f4SDimitry Andric 
344e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
345480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
346480093f4SDimitry Andric       if (!HState || HState->isEscaped())
347480093f4SDimitry Andric         continue;
348480093f4SDimitry Andric 
349e8d8bef9SDimitry Andric       if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
350e8d8bef9SDimitry Andric           PVD->getType()->isIntegerType()) {
351480093f4SDimitry Andric         if (HState->isReleased()) {
352480093f4SDimitry Andric           reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
353480093f4SDimitry Andric           return;
354480093f4SDimitry Andric         }
355480093f4SDimitry Andric       }
356480093f4SDimitry Andric     }
357480093f4SDimitry Andric   }
358480093f4SDimitry Andric   C.addTransition(State);
359480093f4SDimitry Andric }
360480093f4SDimitry Andric 
checkPostCall(const CallEvent & Call,CheckerContext & C) const361480093f4SDimitry Andric void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
362480093f4SDimitry Andric                                          CheckerContext &C) const {
363480093f4SDimitry Andric   const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
364480093f4SDimitry Andric   if (!FuncDecl)
365480093f4SDimitry Andric     return;
366480093f4SDimitry Andric 
367e8d8bef9SDimitry Andric   // If we analyzed the function body, then ignore the annotations.
368e8d8bef9SDimitry Andric   if (C.wasInlined)
369e8d8bef9SDimitry Andric     return;
370e8d8bef9SDimitry Andric 
371480093f4SDimitry Andric   ProgramStateRef State = C.getState();
372480093f4SDimitry Andric 
373480093f4SDimitry Andric   std::vector<std::function<std::string(BugReport & BR)>> Notes;
374480093f4SDimitry Andric   SymbolRef ResultSymbol = nullptr;
375480093f4SDimitry Andric   if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
376480093f4SDimitry Andric     if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
377480093f4SDimitry Andric       ResultSymbol = Call.getReturnValue().getAsSymbol();
378480093f4SDimitry Andric 
379480093f4SDimitry Andric   // Function returns an open handle.
380480093f4SDimitry Andric   if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
381480093f4SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3825ffd83dbSDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3835ffd83dbSDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
384*5f757f3fSDimitry Andric       if (PathBR->getInterestingnessKind(RetSym)) {
3855ffd83dbSDimitry Andric         std::string SBuf;
3865ffd83dbSDimitry Andric         llvm::raw_string_ostream OS(SBuf);
387e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
3885ffd83dbSDimitry Andric            << "' returns an open handle";
3890eae32dcSDimitry Andric         return SBuf;
3905ffd83dbSDimitry Andric       } else
3915ffd83dbSDimitry Andric         return "";
3925ffd83dbSDimitry Andric     });
393480093f4SDimitry Andric     State =
394480093f4SDimitry Andric         State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
395e8d8bef9SDimitry Andric   } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(FuncDecl)) {
396e8d8bef9SDimitry Andric     // Function returns an unowned handle
397e8d8bef9SDimitry Andric     SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
398e8d8bef9SDimitry Andric     Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
399e8d8bef9SDimitry Andric       auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
400*5f757f3fSDimitry Andric       if (PathBR->getInterestingnessKind(RetSym)) {
401e8d8bef9SDimitry Andric         std::string SBuf;
402e8d8bef9SDimitry Andric         llvm::raw_string_ostream OS(SBuf);
403e8d8bef9SDimitry Andric         OS << "Function '" << FuncDecl->getDeclName()
404e8d8bef9SDimitry Andric            << "' returns an unowned handle";
4050eae32dcSDimitry Andric         return SBuf;
406e8d8bef9SDimitry Andric       } else
407e8d8bef9SDimitry Andric         return "";
408e8d8bef9SDimitry Andric     });
409e8d8bef9SDimitry Andric     State = State->set<HStateMap>(RetSym, HandleState::getUnowned());
410480093f4SDimitry Andric   }
411480093f4SDimitry Andric 
412480093f4SDimitry Andric   for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
413480093f4SDimitry Andric     if (Arg >= FuncDecl->getNumParams())
414480093f4SDimitry Andric       break;
415480093f4SDimitry Andric     const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
4165ffd83dbSDimitry Andric     unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
417e8d8bef9SDimitry Andric     SmallVector<SymbolRef, 1024> Handles =
418e8d8bef9SDimitry Andric         getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
419480093f4SDimitry Andric 
420e8d8bef9SDimitry Andric     for (SymbolRef Handle : Handles) {
421480093f4SDimitry Andric       const HandleState *HState = State->get<HStateMap>(Handle);
422480093f4SDimitry Andric       if (HState && HState->isEscaped())
423480093f4SDimitry Andric         continue;
424480093f4SDimitry Andric       if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
425480093f4SDimitry Andric         if (HState && HState->isReleased()) {
426480093f4SDimitry Andric           reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
427480093f4SDimitry Andric           return;
428e8d8bef9SDimitry Andric         } else if (HState && HState->isUnowned()) {
429e8d8bef9SDimitry Andric           reportUnownedRelease(Handle, Call.getArgSourceRange(Arg), C);
430e8d8bef9SDimitry Andric           return;
431480093f4SDimitry Andric         } else {
4325ffd83dbSDimitry Andric           Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
433480093f4SDimitry Andric             auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
434*5f757f3fSDimitry Andric             if (PathBR->getInterestingnessKind(Handle)) {
4355ffd83dbSDimitry Andric               std::string SBuf;
4365ffd83dbSDimitry Andric               llvm::raw_string_ostream OS(SBuf);
4375ffd83dbSDimitry Andric               OS << "Handle released through " << ParamDiagIdx
4385ffd83dbSDimitry Andric                  << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4390eae32dcSDimitry Andric               return SBuf;
440480093f4SDimitry Andric             } else
441480093f4SDimitry Andric               return "";
442480093f4SDimitry Andric           });
443480093f4SDimitry Andric           State = State->set<HStateMap>(Handle, HandleState::getReleased());
444480093f4SDimitry Andric         }
445480093f4SDimitry Andric       } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
4465ffd83dbSDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
447480093f4SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
448*5f757f3fSDimitry Andric           if (PathBR->getInterestingnessKind(Handle)) {
4495ffd83dbSDimitry Andric             std::string SBuf;
4505ffd83dbSDimitry Andric             llvm::raw_string_ostream OS(SBuf);
4515ffd83dbSDimitry Andric             OS << "Handle allocated through " << ParamDiagIdx
4525ffd83dbSDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4530eae32dcSDimitry Andric             return SBuf;
454480093f4SDimitry Andric           } else
455480093f4SDimitry Andric             return "";
456480093f4SDimitry Andric         });
457480093f4SDimitry Andric         State = State->set<HStateMap>(
458480093f4SDimitry Andric             Handle, HandleState::getMaybeAllocated(ResultSymbol));
459e8d8bef9SDimitry Andric       } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
460e8d8bef9SDimitry Andric         Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
461e8d8bef9SDimitry Andric           auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
462*5f757f3fSDimitry Andric           if (PathBR->getInterestingnessKind(Handle)) {
463e8d8bef9SDimitry Andric             std::string SBuf;
464e8d8bef9SDimitry Andric             llvm::raw_string_ostream OS(SBuf);
465e8d8bef9SDimitry Andric             OS << "Unowned handle allocated through " << ParamDiagIdx
466e8d8bef9SDimitry Andric                << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
4670eae32dcSDimitry Andric             return SBuf;
468e8d8bef9SDimitry Andric           } else
469e8d8bef9SDimitry Andric             return "";
470e8d8bef9SDimitry Andric         });
471e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getUnowned());
472e8d8bef9SDimitry Andric       } else if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
473e8d8bef9SDimitry Andric                  PVD->getType()->isIntegerType()) {
474e8d8bef9SDimitry Andric         // Working around integer by-value escapes.
475e8d8bef9SDimitry Andric         // The by-value escape would not be captured in checkPointerEscape.
476e8d8bef9SDimitry Andric         // If the function was not analyzed (otherwise wasInlined should be
477e8d8bef9SDimitry Andric         // true) and there is no annotation on the handle, we assume the handle
478e8d8bef9SDimitry Andric         // is escaped.
479e8d8bef9SDimitry Andric         State = State->set<HStateMap>(Handle, HandleState::getEscaped());
480e8d8bef9SDimitry Andric       }
481480093f4SDimitry Andric     }
482480093f4SDimitry Andric   }
483480093f4SDimitry Andric   const NoteTag *T = nullptr;
484480093f4SDimitry Andric   if (!Notes.empty()) {
4855ffd83dbSDimitry Andric     T = C.getNoteTag([this, Notes{std::move(Notes)}](
4865ffd83dbSDimitry Andric                          PathSensitiveBugReport &BR) -> std::string {
487480093f4SDimitry Andric       if (&BR.getBugType() != &UseAfterReleaseBugType &&
488480093f4SDimitry Andric           &BR.getBugType() != &LeakBugType &&
489e8d8bef9SDimitry Andric           &BR.getBugType() != &DoubleReleaseBugType &&
490e8d8bef9SDimitry Andric           &BR.getBugType() != &ReleaseUnownedBugType)
491480093f4SDimitry Andric         return "";
492480093f4SDimitry Andric       for (auto &Note : Notes) {
493480093f4SDimitry Andric         std::string Text = Note(BR);
494480093f4SDimitry Andric         if (!Text.empty())
495480093f4SDimitry Andric           return Text;
496480093f4SDimitry Andric       }
497480093f4SDimitry Andric       return "";
498480093f4SDimitry Andric     });
499480093f4SDimitry Andric   }
500480093f4SDimitry Andric   C.addTransition(State, T);
501480093f4SDimitry Andric }
502480093f4SDimitry Andric 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const503480093f4SDimitry Andric void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
504480093f4SDimitry Andric                                             CheckerContext &C) const {
505480093f4SDimitry Andric   ProgramStateRef State = C.getState();
506480093f4SDimitry Andric   SmallVector<SymbolRef, 2> LeakedSyms;
507480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
508480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
5095ffd83dbSDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
5105ffd83dbSDimitry Andric     // Keeping zombie handle symbols. In case the error symbol is dying later
5115ffd83dbSDimitry Andric     // than the handle symbol we might produce spurious leak warnings (in case
5125ffd83dbSDimitry Andric     // we find out later from the status code that the handle allocation failed
5135ffd83dbSDimitry Andric     // in the first place).
5145ffd83dbSDimitry Andric     if (!SymReaper.isDead(CurItem.first) ||
5155ffd83dbSDimitry Andric         (ErrorSym && !SymReaper.isDead(ErrorSym)))
516480093f4SDimitry Andric       continue;
517480093f4SDimitry Andric     if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
518480093f4SDimitry Andric       LeakedSyms.push_back(CurItem.first);
519480093f4SDimitry Andric     State = State->remove<HStateMap>(CurItem.first);
520480093f4SDimitry Andric   }
521480093f4SDimitry Andric 
522480093f4SDimitry Andric   ExplodedNode *N = C.getPredecessor();
523480093f4SDimitry Andric   if (!LeakedSyms.empty())
524480093f4SDimitry Andric     N = reportLeaks(LeakedSyms, C, N);
525480093f4SDimitry Andric 
526480093f4SDimitry Andric   C.addTransition(State, N);
527480093f4SDimitry Andric }
528480093f4SDimitry Andric 
529480093f4SDimitry Andric // Acquiring a handle is not always successful. In Fuchsia most functions
530480093f4SDimitry Andric // return a status code that determines the status of the handle.
531480093f4SDimitry Andric // When we split the path based on this status code we know that on one
532480093f4SDimitry Andric // path we do have the handle and on the other path the acquire failed.
533480093f4SDimitry Andric // This method helps avoiding false positive leak warnings on paths where
534480093f4SDimitry Andric // the function failed.
535480093f4SDimitry Andric // Moreover, when a handle is known to be zero (the invalid handle),
536480093f4SDimitry Andric // we no longer can follow the symbol on the path, becaue the constant
537480093f4SDimitry Andric // zero will be used instead of the symbol. We also do not need to release
538480093f4SDimitry Andric // an invalid handle, so we remove the corresponding symbol from the state.
evalAssume(ProgramStateRef State,SVal Cond,bool Assumption) const539480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
540480093f4SDimitry Andric                                                  SVal Cond,
541480093f4SDimitry Andric                                                  bool Assumption) const {
542480093f4SDimitry Andric   // TODO: add notes about successes/fails for APIs.
543480093f4SDimitry Andric   ConstraintManager &Cmr = State->getConstraintManager();
544480093f4SDimitry Andric   HStateMapTy TrackedHandles = State->get<HStateMap>();
545480093f4SDimitry Andric   for (auto &CurItem : TrackedHandles) {
546480093f4SDimitry Andric     ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
547480093f4SDimitry Andric     if (HandleVal.isConstrainedTrue()) {
548480093f4SDimitry Andric       // The handle is invalid. We can no longer follow the symbol on this path.
549480093f4SDimitry Andric       State = State->remove<HStateMap>(CurItem.first);
550480093f4SDimitry Andric     }
551480093f4SDimitry Andric     SymbolRef ErrorSym = CurItem.second.getErrorSym();
552480093f4SDimitry Andric     if (!ErrorSym)
553480093f4SDimitry Andric       continue;
554480093f4SDimitry Andric     ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
555480093f4SDimitry Andric     if (ErrorVal.isConstrainedTrue()) {
556480093f4SDimitry Andric       // Allocation succeeded.
557480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
558480093f4SDimitry Andric         State = State->set<HStateMap>(
559480093f4SDimitry Andric             CurItem.first, HandleState::getAllocated(State, CurItem.second));
560480093f4SDimitry Andric     } else if (ErrorVal.isConstrainedFalse()) {
561480093f4SDimitry Andric       // Allocation failed.
562480093f4SDimitry Andric       if (CurItem.second.maybeAllocated())
563480093f4SDimitry Andric         State = State->remove<HStateMap>(CurItem.first);
564480093f4SDimitry Andric     }
565480093f4SDimitry Andric   }
566480093f4SDimitry Andric   return State;
567480093f4SDimitry Andric }
568480093f4SDimitry Andric 
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const569480093f4SDimitry Andric ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
570480093f4SDimitry Andric     ProgramStateRef State, const InvalidatedSymbols &Escaped,
571480093f4SDimitry Andric     const CallEvent *Call, PointerEscapeKind Kind) const {
572480093f4SDimitry Andric   const FunctionDecl *FuncDecl =
573480093f4SDimitry Andric       Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
574480093f4SDimitry Andric 
575480093f4SDimitry Andric   llvm::DenseSet<SymbolRef> UnEscaped;
576480093f4SDimitry Andric   // Not all calls should escape our symbols.
577480093f4SDimitry Andric   if (FuncDecl &&
578480093f4SDimitry Andric       (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
579480093f4SDimitry Andric        Kind == PSK_EscapeOutParameters)) {
580480093f4SDimitry Andric     for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
581480093f4SDimitry Andric       if (Arg >= FuncDecl->getNumParams())
582480093f4SDimitry Andric         break;
583480093f4SDimitry Andric       const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
584e8d8bef9SDimitry Andric       SmallVector<SymbolRef, 1024> Handles =
585e8d8bef9SDimitry Andric           getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State);
586e8d8bef9SDimitry Andric       for (SymbolRef Handle : Handles) {
587480093f4SDimitry Andric         if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
588e8d8bef9SDimitry Andric             hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
589480093f4SDimitry Andric           UnEscaped.insert(Handle);
590480093f4SDimitry Andric         }
591480093f4SDimitry Andric       }
592e8d8bef9SDimitry Andric     }
593e8d8bef9SDimitry Andric   }
594480093f4SDimitry Andric 
595480093f4SDimitry Andric   // For out params, we have to deal with derived symbols. See
596480093f4SDimitry Andric   // MacOSKeychainAPIChecker for details.
597480093f4SDimitry Andric   for (auto I : State->get<HStateMap>()) {
598480093f4SDimitry Andric     if (Escaped.count(I.first) && !UnEscaped.count(I.first))
599480093f4SDimitry Andric       State = State->set<HStateMap>(I.first, HandleState::getEscaped());
600480093f4SDimitry Andric     if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
601480093f4SDimitry Andric       auto ParentSym = SD->getParentSymbol();
602480093f4SDimitry Andric       if (Escaped.count(ParentSym))
603480093f4SDimitry Andric         State = State->set<HStateMap>(I.first, HandleState::getEscaped());
604480093f4SDimitry Andric     }
605480093f4SDimitry Andric   }
606480093f4SDimitry Andric 
607480093f4SDimitry Andric   return State;
608480093f4SDimitry Andric }
609480093f4SDimitry Andric 
610480093f4SDimitry Andric ExplodedNode *
reportLeaks(ArrayRef<SymbolRef> LeakedHandles,CheckerContext & C,ExplodedNode * Pred) const611480093f4SDimitry Andric FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
612480093f4SDimitry Andric                                   CheckerContext &C, ExplodedNode *Pred) const {
613480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
614480093f4SDimitry Andric   for (SymbolRef LeakedHandle : LeakedHandles) {
615480093f4SDimitry Andric     reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
616480093f4SDimitry Andric               "Potential leak of handle");
617480093f4SDimitry Andric   }
618480093f4SDimitry Andric   return ErrNode;
619480093f4SDimitry Andric }
620480093f4SDimitry Andric 
reportDoubleRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const621480093f4SDimitry Andric void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
622480093f4SDimitry Andric                                                const SourceRange &Range,
623480093f4SDimitry Andric                                                CheckerContext &C) const {
624480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
625480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
626480093f4SDimitry Andric             "Releasing a previously released handle");
627480093f4SDimitry Andric }
628480093f4SDimitry Andric 
reportUnownedRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const629e8d8bef9SDimitry Andric void FuchsiaHandleChecker::reportUnownedRelease(SymbolRef HandleSym,
630e8d8bef9SDimitry Andric                                                 const SourceRange &Range,
631e8d8bef9SDimitry Andric                                                 CheckerContext &C) const {
632e8d8bef9SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
633e8d8bef9SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, ReleaseUnownedBugType,
634e8d8bef9SDimitry Andric             "Releasing an unowned handle");
635e8d8bef9SDimitry Andric }
636e8d8bef9SDimitry Andric 
reportUseAfterFree(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const637480093f4SDimitry Andric void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
638480093f4SDimitry Andric                                               const SourceRange &Range,
639480093f4SDimitry Andric                                               CheckerContext &C) const {
640480093f4SDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
641480093f4SDimitry Andric   reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
642480093f4SDimitry Andric             "Using a previously released handle");
643480093f4SDimitry Andric }
644480093f4SDimitry Andric 
reportBug(SymbolRef Sym,ExplodedNode * ErrorNode,CheckerContext & C,const SourceRange * Range,const BugType & Type,StringRef Msg) const645480093f4SDimitry Andric void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
646480093f4SDimitry Andric                                      CheckerContext &C,
647480093f4SDimitry Andric                                      const SourceRange *Range,
648480093f4SDimitry Andric                                      const BugType &Type, StringRef Msg) const {
649480093f4SDimitry Andric   if (!ErrorNode)
650480093f4SDimitry Andric     return;
651480093f4SDimitry Andric 
652480093f4SDimitry Andric   std::unique_ptr<PathSensitiveBugReport> R;
653480093f4SDimitry Andric   if (Type.isSuppressOnSink()) {
654480093f4SDimitry Andric     const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
655480093f4SDimitry Andric     if (AcquireNode) {
656*5f757f3fSDimitry Andric       const Stmt *S = AcquireNode->getStmtForDiagnostics();
657*5f757f3fSDimitry Andric       assert(S && "Statement cannot be null.");
658480093f4SDimitry Andric       PathDiagnosticLocation LocUsedForUniqueing =
659480093f4SDimitry Andric           PathDiagnosticLocation::createBegin(
660*5f757f3fSDimitry Andric               S, C.getSourceManager(), AcquireNode->getLocationContext());
661480093f4SDimitry Andric 
662480093f4SDimitry Andric       R = std::make_unique<PathSensitiveBugReport>(
663480093f4SDimitry Andric           Type, Msg, ErrorNode, LocUsedForUniqueing,
664480093f4SDimitry Andric           AcquireNode->getLocationContext()->getDecl());
665480093f4SDimitry Andric     }
666480093f4SDimitry Andric   }
667480093f4SDimitry Andric   if (!R)
668480093f4SDimitry Andric     R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
669480093f4SDimitry Andric   if (Range)
670480093f4SDimitry Andric     R->addRange(*Range);
671480093f4SDimitry Andric   R->markInteresting(Sym);
672480093f4SDimitry Andric   C.emitReport(std::move(R));
673480093f4SDimitry Andric }
674480093f4SDimitry Andric 
registerFuchsiaHandleChecker(CheckerManager & mgr)675480093f4SDimitry Andric void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
676480093f4SDimitry Andric   mgr.registerChecker<FuchsiaHandleChecker>();
677480093f4SDimitry Andric }
678480093f4SDimitry Andric 
shouldRegisterFuchsiaHandleChecker(const CheckerManager & mgr)6795ffd83dbSDimitry Andric bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
680480093f4SDimitry Andric   return true;
681480093f4SDimitry Andric }
682480093f4SDimitry Andric 
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const683480093f4SDimitry Andric void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
684480093f4SDimitry Andric                                       const char *NL, const char *Sep) const {
685480093f4SDimitry Andric 
686480093f4SDimitry Andric   HStateMapTy StateMap = State->get<HStateMap>();
687480093f4SDimitry Andric 
688480093f4SDimitry Andric   if (!StateMap.isEmpty()) {
689480093f4SDimitry Andric     Out << Sep << "FuchsiaHandleChecker :" << NL;
69006c3fb27SDimitry Andric     for (const auto &[Sym, HandleState] : StateMap) {
69106c3fb27SDimitry Andric       Sym->dumpToStream(Out);
692480093f4SDimitry Andric       Out << " : ";
69306c3fb27SDimitry Andric       HandleState.dump(Out);
694480093f4SDimitry Andric       Out << NL;
695480093f4SDimitry Andric     }
696480093f4SDimitry Andric   }
697480093f4SDimitry Andric }
698