182923c71SGabor Horvath //=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=//
282923c71SGabor Horvath //
382923c71SGabor Horvath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
482923c71SGabor Horvath // See https://llvm.org/LICENSE.txt for license information.
582923c71SGabor Horvath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
682923c71SGabor Horvath //
782923c71SGabor Horvath //===----------------------------------------------------------------------===//
882923c71SGabor Horvath //
982923c71SGabor Horvath // This checker checks if the handle of Fuchsia is properly used according to
1082923c71SGabor Horvath // following rules.
1182923c71SGabor Horvath // - If a handle is acquired, it should be released before execution
1282923c71SGabor Horvath // ends.
1382923c71SGabor Horvath // - If a handle is released, it should not be released again.
1482923c71SGabor Horvath // - If a handle is released, it should not be used for other purposes
1582923c71SGabor Horvath // such as I/O.
1682923c71SGabor Horvath //
1782923c71SGabor Horvath // In this checker, each tracked handle is associated with a state. When the
1882923c71SGabor Horvath // handle variable is passed to different function calls or syscalls, its state
1982923c71SGabor Horvath // changes. The state changes can be generally represented by following ASCII
2082923c71SGabor Horvath // Art:
2182923c71SGabor Horvath //
2282923c71SGabor Horvath //
238deaec12SDaniel Hwang // +-------------+ +------------+
2482923c71SGabor Horvath // acquire_func succeeded | | Escape | |
2582923c71SGabor Horvath // +-----------------> Allocated +---------> Escaped <--+
2682923c71SGabor Horvath // | | | | | |
2782923c71SGabor Horvath // | +-----+------++ +------------+ |
2882923c71SGabor Horvath // | | | |
298deaec12SDaniel Hwang // acquire_func | release_func | +--+ |
308deaec12SDaniel Hwang // failed | | | handle +--------+ |
318deaec12SDaniel Hwang // +---------+ | | | dies | | |
328deaec12SDaniel Hwang // | | | +----v-----+ +---------> Leaked | |
338deaec12SDaniel Hwang // | | | | | |(REPORT)| |
348deaec12SDaniel Hwang // | +----------+--+ | Released | Escape +--------+ |
358deaec12SDaniel Hwang // | | | | +---------------------------+
368deaec12SDaniel Hwang // +--> Not tracked | +----+---+-+
378deaec12SDaniel Hwang // | | | | As argument by value
388deaec12SDaniel Hwang // +----------+--+ release_func | +------+ in function call
398deaec12SDaniel Hwang // | | | or by reference in
408deaec12SDaniel Hwang // | | | use_func call
418deaec12SDaniel Hwang // unowned | +----v-----+ | +-----------+
428deaec12SDaniel Hwang // acquire_func | | Double | +-----> Use after |
438deaec12SDaniel Hwang // succeeded | | released | | released |
448deaec12SDaniel Hwang // | | (REPORT) | | (REPORT) |
458deaec12SDaniel Hwang // +---------------+ +----------+ +-----------+
468deaec12SDaniel Hwang // | Allocated |
478deaec12SDaniel Hwang // | Unowned | release_func
488deaec12SDaniel Hwang // | +---------+
498deaec12SDaniel Hwang // +---------------+ |
508deaec12SDaniel Hwang // |
518deaec12SDaniel Hwang // +-----v----------+
528deaec12SDaniel Hwang // | Release of |
538deaec12SDaniel Hwang // | unowned handle |
548deaec12SDaniel Hwang // | (REPORT) |
558deaec12SDaniel Hwang // +----------------+
5682923c71SGabor Horvath //
5782923c71SGabor Horvath // acquire_func represents the functions or syscalls that may acquire a handle.
5882923c71SGabor Horvath // release_func represents the functions or syscalls that may release a handle.
5982923c71SGabor Horvath // use_func represents the functions or syscall that requires an open handle.
6082923c71SGabor Horvath //
6182923c71SGabor Horvath // If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
6282923c71SGabor Horvath // is properly used. Otherwise a bug and will be reported.
6382923c71SGabor Horvath //
6482923c71SGabor Horvath // Note that, the analyzer does not always know for sure if a function failed
6582923c71SGabor Horvath // or succeeded. In those cases we use the state MaybeAllocated.
66914f6c4fSHaowei Wu // Thus, the diagram above captures the intent, not implementation details.
6782923c71SGabor Horvath //
6882923c71SGabor Horvath // Due to the fact that the number of handle related syscalls in Fuchsia
6982923c71SGabor Horvath // is large, we adopt the annotation attributes to descript syscalls'
7082923c71SGabor Horvath // operations(acquire/release/use) on handles instead of hardcoding
7182923c71SGabor Horvath // everything in the checker.
7282923c71SGabor Horvath //
7382923c71SGabor Horvath // We use following annotation attributes for handle related syscalls or
7482923c71SGabor Horvath // functions:
7582923c71SGabor Horvath // 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
7682923c71SGabor Horvath // 2. __attribute__((release_handle("Fuchsia"))) |handle will be released
7782923c71SGabor Horvath // 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
7882923c71SGabor Horvath // escaped state, it also needs to be open.
7982923c71SGabor Horvath //
8082923c71SGabor Horvath // For example, an annotated syscall:
8182923c71SGabor Horvath // zx_status_t zx_channel_create(
8282923c71SGabor Horvath // uint32_t options,
8382923c71SGabor Horvath // zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
8482923c71SGabor Horvath // zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
8582923c71SGabor Horvath // denotes a syscall which will acquire two handles and save them to 'out0' and
8682923c71SGabor Horvath // 'out1' when succeeded.
8782923c71SGabor Horvath //
8882923c71SGabor Horvath //===----------------------------------------------------------------------===//
8982923c71SGabor Horvath
9082923c71SGabor Horvath #include "clang/AST/Attr.h"
9182923c71SGabor Horvath #include "clang/AST/Decl.h"
9282923c71SGabor Horvath #include "clang/AST/Type.h"
9382923c71SGabor Horvath #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
9482923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
9582923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/Checker.h"
9682923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/CheckerManager.h"
9782923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
9882923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
9982923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
10082923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
10182923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
10282923c71SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
10376221c73SReid Kleckner #include "llvm/ADT/StringExtras.h"
10482923c71SGabor Horvath
10582923c71SGabor Horvath using namespace clang;
10682923c71SGabor Horvath using namespace ento;
10782923c71SGabor Horvath
10882923c71SGabor Horvath namespace {
10982923c71SGabor Horvath
11082923c71SGabor Horvath static const StringRef HandleTypeName = "zx_handle_t";
11182923c71SGabor Horvath static const StringRef ErrorTypeName = "zx_status_t";
11282923c71SGabor Horvath
11382923c71SGabor Horvath class HandleState {
11482923c71SGabor Horvath private:
1158deaec12SDaniel Hwang enum class Kind { MaybeAllocated, Allocated, Released, Escaped, Unowned } K;
11682923c71SGabor Horvath SymbolRef ErrorSym;
HandleState(Kind K,SymbolRef ErrorSym)11782923c71SGabor Horvath HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
11882923c71SGabor Horvath
11982923c71SGabor Horvath public:
operator ==(const HandleState & Other) const12082923c71SGabor Horvath bool operator==(const HandleState &Other) const {
12182923c71SGabor Horvath return K == Other.K && ErrorSym == Other.ErrorSym;
12282923c71SGabor Horvath }
isAllocated() const12382923c71SGabor Horvath bool isAllocated() const { return K == Kind::Allocated; }
maybeAllocated() const12482923c71SGabor Horvath bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
isReleased() const12582923c71SGabor Horvath bool isReleased() const { return K == Kind::Released; }
isEscaped() const12682923c71SGabor Horvath bool isEscaped() const { return K == Kind::Escaped; }
isUnowned() const1278deaec12SDaniel Hwang bool isUnowned() const { return K == Kind::Unowned; }
12882923c71SGabor Horvath
getMaybeAllocated(SymbolRef ErrorSym)12982923c71SGabor Horvath static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
13082923c71SGabor Horvath return HandleState(Kind::MaybeAllocated, ErrorSym);
13182923c71SGabor Horvath }
getAllocated(ProgramStateRef State,HandleState S)13282923c71SGabor Horvath static HandleState getAllocated(ProgramStateRef State, HandleState S) {
13382923c71SGabor Horvath assert(S.maybeAllocated());
13482923c71SGabor Horvath assert(State->getConstraintManager()
13582923c71SGabor Horvath .isNull(State, S.getErrorSym())
13682923c71SGabor Horvath .isConstrained());
13782923c71SGabor Horvath return HandleState(Kind::Allocated, nullptr);
13882923c71SGabor Horvath }
getReleased()13982923c71SGabor Horvath static HandleState getReleased() {
14082923c71SGabor Horvath return HandleState(Kind::Released, nullptr);
14182923c71SGabor Horvath }
getEscaped()14282923c71SGabor Horvath static HandleState getEscaped() {
14382923c71SGabor Horvath return HandleState(Kind::Escaped, nullptr);
14482923c71SGabor Horvath }
getUnowned()1458deaec12SDaniel Hwang static HandleState getUnowned() {
1468deaec12SDaniel Hwang return HandleState(Kind::Unowned, nullptr);
1478deaec12SDaniel Hwang }
14882923c71SGabor Horvath
getErrorSym() const14982923c71SGabor Horvath SymbolRef getErrorSym() const { return ErrorSym; }
15082923c71SGabor Horvath
Profile(llvm::FoldingSetNodeID & ID) const15182923c71SGabor Horvath void Profile(llvm::FoldingSetNodeID &ID) const {
15282923c71SGabor Horvath ID.AddInteger(static_cast<int>(K));
15382923c71SGabor Horvath ID.AddPointer(ErrorSym);
15482923c71SGabor Horvath }
15582923c71SGabor Horvath
dump(raw_ostream & OS) const15682923c71SGabor Horvath LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
15782923c71SGabor Horvath switch (K) {
15882923c71SGabor Horvath #define CASE(ID) \
15982923c71SGabor Horvath case ID: \
16082923c71SGabor Horvath OS << #ID; \
16182923c71SGabor Horvath break;
16282923c71SGabor Horvath CASE(Kind::MaybeAllocated)
16382923c71SGabor Horvath CASE(Kind::Allocated)
16482923c71SGabor Horvath CASE(Kind::Released)
16582923c71SGabor Horvath CASE(Kind::Escaped)
1668deaec12SDaniel Hwang CASE(Kind::Unowned)
16782923c71SGabor Horvath }
168c98d98baSGabor Horvath if (ErrorSym) {
169c98d98baSGabor Horvath OS << " ErrorSym: ";
170c98d98baSGabor Horvath ErrorSym->dumpToStream(OS);
171c98d98baSGabor Horvath }
17282923c71SGabor Horvath }
17382923c71SGabor Horvath
dump() const17482923c71SGabor Horvath LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
17582923c71SGabor Horvath };
17682923c71SGabor Horvath
hasFuchsiaAttr(const Decl * D)17782923c71SGabor Horvath template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
17882923c71SGabor Horvath return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
17982923c71SGabor Horvath }
18082923c71SGabor Horvath
hasFuchsiaUnownedAttr(const Decl * D)1818deaec12SDaniel Hwang template <typename Attr> static bool hasFuchsiaUnownedAttr(const Decl *D) {
1828deaec12SDaniel Hwang return D->hasAttr<Attr>() &&
1838deaec12SDaniel Hwang D->getAttr<Attr>()->getHandleType() == "FuchsiaUnowned";
1848deaec12SDaniel Hwang }
1858deaec12SDaniel Hwang
18682923c71SGabor Horvath class FuchsiaHandleChecker
18782923c71SGabor Horvath : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
18882923c71SGabor Horvath check::PointerEscape, eval::Assume> {
18982923c71SGabor Horvath BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
19082923c71SGabor Horvath /*SuppressOnSink=*/true};
19182923c71SGabor Horvath BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
19282923c71SGabor Horvath "Fuchsia Handle Error"};
19382923c71SGabor Horvath BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
19482923c71SGabor Horvath "Fuchsia Handle Error"};
1958deaec12SDaniel Hwang BugType ReleaseUnownedBugType{
1968deaec12SDaniel Hwang this, "Fuchsia handle release of unowned handle", "Fuchsia Handle Error"};
19782923c71SGabor Horvath
19882923c71SGabor Horvath public:
19982923c71SGabor Horvath void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
20082923c71SGabor Horvath void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
20182923c71SGabor Horvath void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
20282923c71SGabor Horvath ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
20382923c71SGabor Horvath bool Assumption) const;
20482923c71SGabor Horvath ProgramStateRef checkPointerEscape(ProgramStateRef State,
20582923c71SGabor Horvath const InvalidatedSymbols &Escaped,
20682923c71SGabor Horvath const CallEvent *Call,
20782923c71SGabor Horvath PointerEscapeKind Kind) const;
20882923c71SGabor Horvath
20982923c71SGabor Horvath ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
21082923c71SGabor Horvath CheckerContext &C, ExplodedNode *Pred) const;
21182923c71SGabor Horvath
21282923c71SGabor Horvath void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
21382923c71SGabor Horvath CheckerContext &C) const;
21482923c71SGabor Horvath
2158deaec12SDaniel Hwang void reportUnownedRelease(SymbolRef HandleSym, const SourceRange &Range,
2168deaec12SDaniel Hwang CheckerContext &C) const;
2178deaec12SDaniel Hwang
21882923c71SGabor Horvath void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
21982923c71SGabor Horvath CheckerContext &C) const;
22082923c71SGabor Horvath
22182923c71SGabor Horvath void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
22282923c71SGabor Horvath const SourceRange *Range, const BugType &Type,
22382923c71SGabor Horvath StringRef Msg) const;
22482923c71SGabor Horvath
22582923c71SGabor Horvath void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
22682923c71SGabor Horvath const char *Sep) const override;
22782923c71SGabor Horvath };
22882923c71SGabor Horvath } // end anonymous namespace
22982923c71SGabor Horvath
REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap,SymbolRef,HandleState) const23082923c71SGabor Horvath REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
23182923c71SGabor Horvath
23259878ec8SGabor Horvath static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
23359878ec8SGabor Horvath CheckerContext &Ctx) {
23459878ec8SGabor Horvath ProgramStateRef State = N->getState();
23559878ec8SGabor Horvath // When bug type is handle leak, exploded node N does not have state info for
23659878ec8SGabor Horvath // leaking handle. Get the predecessor of N instead.
23759878ec8SGabor Horvath if (!State->get<HStateMap>(Sym))
23859878ec8SGabor Horvath N = N->getFirstPred();
23959878ec8SGabor Horvath
24059878ec8SGabor Horvath const ExplodedNode *Pred = N;
24159878ec8SGabor Horvath while (N) {
24259878ec8SGabor Horvath State = N->getState();
24359878ec8SGabor Horvath if (!State->get<HStateMap>(Sym)) {
24459878ec8SGabor Horvath const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
24559878ec8SGabor Horvath if (HState && (HState->isAllocated() || HState->maybeAllocated()))
24659878ec8SGabor Horvath return N;
24759878ec8SGabor Horvath }
24859878ec8SGabor Horvath Pred = N;
24959878ec8SGabor Horvath N = N->getFirstPred();
25059878ec8SGabor Horvath }
25159878ec8SGabor Horvath return nullptr;
25259878ec8SGabor Horvath }
25359878ec8SGabor Horvath
254914f6c4fSHaowei Wu namespace {
255914f6c4fSHaowei Wu class FuchsiaHandleSymbolVisitor final : public SymbolVisitor {
256914f6c4fSHaowei Wu public:
VisitSymbol(SymbolRef S)257914f6c4fSHaowei Wu bool VisitSymbol(SymbolRef S) override {
258914f6c4fSHaowei Wu if (const auto *HandleType = S->getType()->getAs<TypedefType>())
259914f6c4fSHaowei Wu if (HandleType->getDecl()->getName() == HandleTypeName)
260914f6c4fSHaowei Wu Symbols.push_back(S);
261914f6c4fSHaowei Wu return true;
262914f6c4fSHaowei Wu }
263914f6c4fSHaowei Wu
GetSymbols()264914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> GetSymbols() { return Symbols; }
265914f6c4fSHaowei Wu
266914f6c4fSHaowei Wu private:
267914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Symbols;
268914f6c4fSHaowei Wu };
269914f6c4fSHaowei Wu } // end anonymous namespace
270914f6c4fSHaowei Wu
271914f6c4fSHaowei Wu /// Returns the symbols extracted from the argument or empty vector if it cannot
272914f6c4fSHaowei Wu /// be found. It is unlikely to have over 1024 symbols in one argument.
273914f6c4fSHaowei Wu static SmallVector<SymbolRef, 1024>
getFuchsiaHandleSymbols(QualType QT,SVal Arg,ProgramStateRef State)274914f6c4fSHaowei Wu getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
27582923c71SGabor Horvath int PtrToHandleLevel = 0;
27682923c71SGabor Horvath while (QT->isAnyPointerType() || QT->isReferenceType()) {
27782923c71SGabor Horvath ++PtrToHandleLevel;
27882923c71SGabor Horvath QT = QT->getPointeeType();
27982923c71SGabor Horvath }
280914f6c4fSHaowei Wu if (QT->isStructureType()) {
281914f6c4fSHaowei Wu // If we see a structure, see if there is any handle referenced by the
282914f6c4fSHaowei Wu // structure.
283*f1b18a79SBalazs Benics FuchsiaHandleSymbolVisitor Visitor;
284914f6c4fSHaowei Wu State->scanReachableSymbols(Arg, Visitor);
285914f6c4fSHaowei Wu return Visitor.GetSymbols();
286914f6c4fSHaowei Wu }
28782923c71SGabor Horvath if (const auto *HandleType = QT->getAs<TypedefType>()) {
28882923c71SGabor Horvath if (HandleType->getDecl()->getName() != HandleTypeName)
289914f6c4fSHaowei Wu return {};
290914f6c4fSHaowei Wu if (PtrToHandleLevel > 1)
29182923c71SGabor Horvath // Not supported yet.
292914f6c4fSHaowei Wu return {};
29382923c71SGabor Horvath
29482923c71SGabor Horvath if (PtrToHandleLevel == 0) {
295914f6c4fSHaowei Wu SymbolRef Sym = Arg.getAsSymbol();
296914f6c4fSHaowei Wu if (Sym) {
297914f6c4fSHaowei Wu return {Sym};
298914f6c4fSHaowei Wu } else {
299914f6c4fSHaowei Wu return {};
300914f6c4fSHaowei Wu }
30182923c71SGabor Horvath } else {
30282923c71SGabor Horvath assert(PtrToHandleLevel == 1);
303914f6c4fSHaowei Wu if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
304914f6c4fSHaowei Wu SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
305914f6c4fSHaowei Wu if (Sym) {
306914f6c4fSHaowei Wu return {Sym};
307914f6c4fSHaowei Wu } else {
308914f6c4fSHaowei Wu return {};
30982923c71SGabor Horvath }
31082923c71SGabor Horvath }
311914f6c4fSHaowei Wu }
312914f6c4fSHaowei Wu }
313914f6c4fSHaowei Wu return {};
31482923c71SGabor Horvath }
31582923c71SGabor Horvath
checkPreCall(const CallEvent & Call,CheckerContext & C) const31682923c71SGabor Horvath void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
31782923c71SGabor Horvath CheckerContext &C) const {
31882923c71SGabor Horvath ProgramStateRef State = C.getState();
31982923c71SGabor Horvath const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
32082923c71SGabor Horvath if (!FuncDecl) {
32182923c71SGabor Horvath // Unknown call, escape by value handles. They are not covered by
32282923c71SGabor Horvath // PointerEscape callback.
32382923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
32482923c71SGabor Horvath if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
32582923c71SGabor Horvath State = State->set<HStateMap>(Handle, HandleState::getEscaped());
32682923c71SGabor Horvath }
32782923c71SGabor Horvath C.addTransition(State);
32882923c71SGabor Horvath return;
32982923c71SGabor Horvath }
33082923c71SGabor Horvath
33182923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
33282923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
33382923c71SGabor Horvath break;
33482923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
335914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
336914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
33782923c71SGabor Horvath
33882923c71SGabor Horvath // Handled in checkPostCall.
33982923c71SGabor Horvath if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
34082923c71SGabor Horvath hasFuchsiaAttr<AcquireHandleAttr>(PVD))
34182923c71SGabor Horvath continue;
34282923c71SGabor Horvath
343914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
34482923c71SGabor Horvath const HandleState *HState = State->get<HStateMap>(Handle);
34582923c71SGabor Horvath if (!HState || HState->isEscaped())
34682923c71SGabor Horvath continue;
34782923c71SGabor Horvath
348914f6c4fSHaowei Wu if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
349914f6c4fSHaowei Wu PVD->getType()->isIntegerType()) {
35082923c71SGabor Horvath if (HState->isReleased()) {
35182923c71SGabor Horvath reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
35282923c71SGabor Horvath return;
35382923c71SGabor Horvath }
35482923c71SGabor Horvath }
35582923c71SGabor Horvath }
356914f6c4fSHaowei Wu }
35782923c71SGabor Horvath C.addTransition(State);
35882923c71SGabor Horvath }
35982923c71SGabor Horvath
checkPostCall(const CallEvent & Call,CheckerContext & C) const36082923c71SGabor Horvath void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
36182923c71SGabor Horvath CheckerContext &C) const {
36282923c71SGabor Horvath const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
36382923c71SGabor Horvath if (!FuncDecl)
36482923c71SGabor Horvath return;
36582923c71SGabor Horvath
3663ce78f54SYu Shan // If we analyzed the function body, then ignore the annotations.
3673ce78f54SYu Shan if (C.wasInlined)
3683ce78f54SYu Shan return;
3693ce78f54SYu Shan
37082923c71SGabor Horvath ProgramStateRef State = C.getState();
37182923c71SGabor Horvath
37259878ec8SGabor Horvath std::vector<std::function<std::string(BugReport & BR)>> Notes;
37382923c71SGabor Horvath SymbolRef ResultSymbol = nullptr;
37482923c71SGabor Horvath if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
37582923c71SGabor Horvath if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
37682923c71SGabor Horvath ResultSymbol = Call.getReturnValue().getAsSymbol();
37782923c71SGabor Horvath
37882923c71SGabor Horvath // Function returns an open handle.
37982923c71SGabor Horvath if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
38082923c71SGabor Horvath SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3815911268eSGabor Horvath Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3825911268eSGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
3835911268eSGabor Horvath if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
3845911268eSGabor Horvath std::string SBuf;
3855911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
38619701458SBruno Ricci OS << "Function '" << FuncDecl->getDeclName()
3875911268eSGabor Horvath << "' returns an open handle";
388715c72b4SLogan Smith return SBuf;
3895911268eSGabor Horvath } else
3905911268eSGabor Horvath return "";
3915911268eSGabor Horvath });
39282923c71SGabor Horvath State =
39382923c71SGabor Horvath State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
3948deaec12SDaniel Hwang } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(FuncDecl)) {
3958deaec12SDaniel Hwang // Function returns an unowned handle
3968deaec12SDaniel Hwang SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3978deaec12SDaniel Hwang Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3988deaec12SDaniel Hwang auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
3998deaec12SDaniel Hwang if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
4008deaec12SDaniel Hwang std::string SBuf;
4018deaec12SDaniel Hwang llvm::raw_string_ostream OS(SBuf);
4028deaec12SDaniel Hwang OS << "Function '" << FuncDecl->getDeclName()
4038deaec12SDaniel Hwang << "' returns an unowned handle";
404715c72b4SLogan Smith return SBuf;
4058deaec12SDaniel Hwang } else
4068deaec12SDaniel Hwang return "";
4078deaec12SDaniel Hwang });
4088deaec12SDaniel Hwang State = State->set<HStateMap>(RetSym, HandleState::getUnowned());
40982923c71SGabor Horvath }
41082923c71SGabor Horvath
41182923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
41282923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
41382923c71SGabor Horvath break;
41482923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
4155911268eSGabor Horvath unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
416914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
417914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
41882923c71SGabor Horvath
419914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
42082923c71SGabor Horvath const HandleState *HState = State->get<HStateMap>(Handle);
42182923c71SGabor Horvath if (HState && HState->isEscaped())
42282923c71SGabor Horvath continue;
42382923c71SGabor Horvath if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
42482923c71SGabor Horvath if (HState && HState->isReleased()) {
42582923c71SGabor Horvath reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
42682923c71SGabor Horvath return;
4278deaec12SDaniel Hwang } else if (HState && HState->isUnowned()) {
4288deaec12SDaniel Hwang reportUnownedRelease(Handle, Call.getArgSourceRange(Arg), C);
4298deaec12SDaniel Hwang return;
43059878ec8SGabor Horvath } else {
4315911268eSGabor Horvath Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
43259878ec8SGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
43359878ec8SGabor Horvath if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4345911268eSGabor Horvath std::string SBuf;
4355911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
4365911268eSGabor Horvath OS << "Handle released through " << ParamDiagIdx
4375911268eSGabor Horvath << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
438715c72b4SLogan Smith return SBuf;
43982923c71SGabor Horvath } else
44059878ec8SGabor Horvath return "";
44159878ec8SGabor Horvath });
44282923c71SGabor Horvath State = State->set<HStateMap>(Handle, HandleState::getReleased());
44359878ec8SGabor Horvath }
44482923c71SGabor Horvath } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
4455911268eSGabor Horvath Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
44659878ec8SGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
44759878ec8SGabor Horvath if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4485911268eSGabor Horvath std::string SBuf;
4495911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
4505911268eSGabor Horvath OS << "Handle allocated through " << ParamDiagIdx
4515911268eSGabor Horvath << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
452715c72b4SLogan Smith return SBuf;
45359878ec8SGabor Horvath } else
45459878ec8SGabor Horvath return "";
45559878ec8SGabor Horvath });
45682923c71SGabor Horvath State = State->set<HStateMap>(
45782923c71SGabor Horvath Handle, HandleState::getMaybeAllocated(ResultSymbol));
4588deaec12SDaniel Hwang } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
4598deaec12SDaniel Hwang Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
4608deaec12SDaniel Hwang auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
4618deaec12SDaniel Hwang if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
4628deaec12SDaniel Hwang std::string SBuf;
4638deaec12SDaniel Hwang llvm::raw_string_ostream OS(SBuf);
4648deaec12SDaniel Hwang OS << "Unowned handle allocated through " << ParamDiagIdx
4658deaec12SDaniel Hwang << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
466715c72b4SLogan Smith return SBuf;
4678deaec12SDaniel Hwang } else
4688deaec12SDaniel Hwang return "";
4698deaec12SDaniel Hwang });
4708deaec12SDaniel Hwang State = State->set<HStateMap>(Handle, HandleState::getUnowned());
4713ce78f54SYu Shan } else if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
4723ce78f54SYu Shan PVD->getType()->isIntegerType()) {
4733ce78f54SYu Shan // Working around integer by-value escapes.
4743ce78f54SYu Shan // The by-value escape would not be captured in checkPointerEscape.
4753ce78f54SYu Shan // If the function was not analyzed (otherwise wasInlined should be
4763ce78f54SYu Shan // true) and there is no annotation on the handle, we assume the handle
4773ce78f54SYu Shan // is escaped.
4783ce78f54SYu Shan State = State->set<HStateMap>(Handle, HandleState::getEscaped());
47982923c71SGabor Horvath }
48082923c71SGabor Horvath }
481914f6c4fSHaowei Wu }
48259878ec8SGabor Horvath const NoteTag *T = nullptr;
48359878ec8SGabor Horvath if (!Notes.empty()) {
48420a3d64cSAdam Balogh T = C.getNoteTag([this, Notes{std::move(Notes)}](
48520a3d64cSAdam Balogh PathSensitiveBugReport &BR) -> std::string {
48659878ec8SGabor Horvath if (&BR.getBugType() != &UseAfterReleaseBugType &&
48759878ec8SGabor Horvath &BR.getBugType() != &LeakBugType &&
4888deaec12SDaniel Hwang &BR.getBugType() != &DoubleReleaseBugType &&
4898deaec12SDaniel Hwang &BR.getBugType() != &ReleaseUnownedBugType)
49059878ec8SGabor Horvath return "";
49159878ec8SGabor Horvath for (auto &Note : Notes) {
49259878ec8SGabor Horvath std::string Text = Note(BR);
49359878ec8SGabor Horvath if (!Text.empty())
49459878ec8SGabor Horvath return Text;
49559878ec8SGabor Horvath }
49659878ec8SGabor Horvath return "";
49759878ec8SGabor Horvath });
49859878ec8SGabor Horvath }
49959878ec8SGabor Horvath C.addTransition(State, T);
50082923c71SGabor Horvath }
50182923c71SGabor Horvath
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const50282923c71SGabor Horvath void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
50382923c71SGabor Horvath CheckerContext &C) const {
50482923c71SGabor Horvath ProgramStateRef State = C.getState();
50582923c71SGabor Horvath SmallVector<SymbolRef, 2> LeakedSyms;
50682923c71SGabor Horvath HStateMapTy TrackedHandles = State->get<HStateMap>();
50782923c71SGabor Horvath for (auto &CurItem : TrackedHandles) {
508c98d98baSGabor Horvath SymbolRef ErrorSym = CurItem.second.getErrorSym();
509c98d98baSGabor Horvath // Keeping zombie handle symbols. In case the error symbol is dying later
510c98d98baSGabor Horvath // than the handle symbol we might produce spurious leak warnings (in case
511c98d98baSGabor Horvath // we find out later from the status code that the handle allocation failed
512c98d98baSGabor Horvath // in the first place).
513c98d98baSGabor Horvath if (!SymReaper.isDead(CurItem.first) ||
514c98d98baSGabor Horvath (ErrorSym && !SymReaper.isDead(ErrorSym)))
51582923c71SGabor Horvath continue;
51682923c71SGabor Horvath if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
51782923c71SGabor Horvath LeakedSyms.push_back(CurItem.first);
51882923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
51982923c71SGabor Horvath }
52082923c71SGabor Horvath
52182923c71SGabor Horvath ExplodedNode *N = C.getPredecessor();
52282923c71SGabor Horvath if (!LeakedSyms.empty())
52382923c71SGabor Horvath N = reportLeaks(LeakedSyms, C, N);
52482923c71SGabor Horvath
52582923c71SGabor Horvath C.addTransition(State, N);
52682923c71SGabor Horvath }
52782923c71SGabor Horvath
52882923c71SGabor Horvath // Acquiring a handle is not always successful. In Fuchsia most functions
52982923c71SGabor Horvath // return a status code that determines the status of the handle.
53082923c71SGabor Horvath // When we split the path based on this status code we know that on one
53182923c71SGabor Horvath // path we do have the handle and on the other path the acquire failed.
53282923c71SGabor Horvath // This method helps avoiding false positive leak warnings on paths where
53382923c71SGabor Horvath // the function failed.
53482923c71SGabor Horvath // Moreover, when a handle is known to be zero (the invalid handle),
53582923c71SGabor Horvath // we no longer can follow the symbol on the path, becaue the constant
53682923c71SGabor Horvath // zero will be used instead of the symbol. We also do not need to release
53782923c71SGabor Horvath // an invalid handle, so we remove the corresponding symbol from the state.
evalAssume(ProgramStateRef State,SVal Cond,bool Assumption) const53882923c71SGabor Horvath ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
53982923c71SGabor Horvath SVal Cond,
54082923c71SGabor Horvath bool Assumption) const {
54159878ec8SGabor Horvath // TODO: add notes about successes/fails for APIs.
54282923c71SGabor Horvath ConstraintManager &Cmr = State->getConstraintManager();
54382923c71SGabor Horvath HStateMapTy TrackedHandles = State->get<HStateMap>();
54482923c71SGabor Horvath for (auto &CurItem : TrackedHandles) {
54582923c71SGabor Horvath ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
54682923c71SGabor Horvath if (HandleVal.isConstrainedTrue()) {
54782923c71SGabor Horvath // The handle is invalid. We can no longer follow the symbol on this path.
54882923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
54982923c71SGabor Horvath }
55082923c71SGabor Horvath SymbolRef ErrorSym = CurItem.second.getErrorSym();
55182923c71SGabor Horvath if (!ErrorSym)
55282923c71SGabor Horvath continue;
55382923c71SGabor Horvath ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
55482923c71SGabor Horvath if (ErrorVal.isConstrainedTrue()) {
55582923c71SGabor Horvath // Allocation succeeded.
55682923c71SGabor Horvath if (CurItem.second.maybeAllocated())
55782923c71SGabor Horvath State = State->set<HStateMap>(
55882923c71SGabor Horvath CurItem.first, HandleState::getAllocated(State, CurItem.second));
55982923c71SGabor Horvath } else if (ErrorVal.isConstrainedFalse()) {
56082923c71SGabor Horvath // Allocation failed.
56182923c71SGabor Horvath if (CurItem.second.maybeAllocated())
56282923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
56382923c71SGabor Horvath }
56482923c71SGabor Horvath }
56582923c71SGabor Horvath return State;
56682923c71SGabor Horvath }
56782923c71SGabor Horvath
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const56882923c71SGabor Horvath ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
56982923c71SGabor Horvath ProgramStateRef State, const InvalidatedSymbols &Escaped,
57082923c71SGabor Horvath const CallEvent *Call, PointerEscapeKind Kind) const {
57182923c71SGabor Horvath const FunctionDecl *FuncDecl =
57282923c71SGabor Horvath Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
57382923c71SGabor Horvath
57482923c71SGabor Horvath llvm::DenseSet<SymbolRef> UnEscaped;
57582923c71SGabor Horvath // Not all calls should escape our symbols.
57682923c71SGabor Horvath if (FuncDecl &&
57782923c71SGabor Horvath (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
57882923c71SGabor Horvath Kind == PSK_EscapeOutParameters)) {
57982923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
58082923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
58182923c71SGabor Horvath break;
58282923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
583914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
584914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State);
585914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
58682923c71SGabor Horvath if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
587914f6c4fSHaowei Wu hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
58882923c71SGabor Horvath UnEscaped.insert(Handle);
58982923c71SGabor Horvath }
59082923c71SGabor Horvath }
591914f6c4fSHaowei Wu }
592914f6c4fSHaowei Wu }
59382923c71SGabor Horvath
59482923c71SGabor Horvath // For out params, we have to deal with derived symbols. See
59582923c71SGabor Horvath // MacOSKeychainAPIChecker for details.
59682923c71SGabor Horvath for (auto I : State->get<HStateMap>()) {
59782923c71SGabor Horvath if (Escaped.count(I.first) && !UnEscaped.count(I.first))
59882923c71SGabor Horvath State = State->set<HStateMap>(I.first, HandleState::getEscaped());
59982923c71SGabor Horvath if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
60082923c71SGabor Horvath auto ParentSym = SD->getParentSymbol();
60182923c71SGabor Horvath if (Escaped.count(ParentSym))
60282923c71SGabor Horvath State = State->set<HStateMap>(I.first, HandleState::getEscaped());
60382923c71SGabor Horvath }
60482923c71SGabor Horvath }
60582923c71SGabor Horvath
60682923c71SGabor Horvath return State;
60782923c71SGabor Horvath }
60882923c71SGabor Horvath
60982923c71SGabor Horvath ExplodedNode *
reportLeaks(ArrayRef<SymbolRef> LeakedHandles,CheckerContext & C,ExplodedNode * Pred) const61082923c71SGabor Horvath FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
61182923c71SGabor Horvath CheckerContext &C, ExplodedNode *Pred) const {
61282923c71SGabor Horvath ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
61382923c71SGabor Horvath for (SymbolRef LeakedHandle : LeakedHandles) {
61482923c71SGabor Horvath reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
61582923c71SGabor Horvath "Potential leak of handle");
61682923c71SGabor Horvath }
61782923c71SGabor Horvath return ErrNode;
61882923c71SGabor Horvath }
61982923c71SGabor Horvath
reportDoubleRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const62082923c71SGabor Horvath void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
62182923c71SGabor Horvath const SourceRange &Range,
62282923c71SGabor Horvath CheckerContext &C) const {
62382923c71SGabor Horvath ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
62482923c71SGabor Horvath reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
62582923c71SGabor Horvath "Releasing a previously released handle");
62682923c71SGabor Horvath }
62782923c71SGabor Horvath
reportUnownedRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const6288deaec12SDaniel Hwang void FuchsiaHandleChecker::reportUnownedRelease(SymbolRef HandleSym,
6298deaec12SDaniel Hwang const SourceRange &Range,
6308deaec12SDaniel Hwang CheckerContext &C) const {
6318deaec12SDaniel Hwang ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
6328deaec12SDaniel Hwang reportBug(HandleSym, ErrNode, C, &Range, ReleaseUnownedBugType,
6338deaec12SDaniel Hwang "Releasing an unowned handle");
6348deaec12SDaniel Hwang }
6358deaec12SDaniel Hwang
reportUseAfterFree(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const63682923c71SGabor Horvath void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
63782923c71SGabor Horvath const SourceRange &Range,
63882923c71SGabor Horvath CheckerContext &C) const {
63982923c71SGabor Horvath ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
64082923c71SGabor Horvath reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
64182923c71SGabor Horvath "Using a previously released handle");
64282923c71SGabor Horvath }
64382923c71SGabor Horvath
reportBug(SymbolRef Sym,ExplodedNode * ErrorNode,CheckerContext & C,const SourceRange * Range,const BugType & Type,StringRef Msg) const64482923c71SGabor Horvath void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
64582923c71SGabor Horvath CheckerContext &C,
64682923c71SGabor Horvath const SourceRange *Range,
64782923c71SGabor Horvath const BugType &Type, StringRef Msg) const {
64882923c71SGabor Horvath if (!ErrorNode)
64982923c71SGabor Horvath return;
65082923c71SGabor Horvath
65159878ec8SGabor Horvath std::unique_ptr<PathSensitiveBugReport> R;
65259878ec8SGabor Horvath if (Type.isSuppressOnSink()) {
65359878ec8SGabor Horvath const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
65459878ec8SGabor Horvath if (AcquireNode) {
65559878ec8SGabor Horvath PathDiagnosticLocation LocUsedForUniqueing =
65659878ec8SGabor Horvath PathDiagnosticLocation::createBegin(
65759878ec8SGabor Horvath AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
65859878ec8SGabor Horvath AcquireNode->getLocationContext());
65959878ec8SGabor Horvath
66059878ec8SGabor Horvath R = std::make_unique<PathSensitiveBugReport>(
66159878ec8SGabor Horvath Type, Msg, ErrorNode, LocUsedForUniqueing,
66259878ec8SGabor Horvath AcquireNode->getLocationContext()->getDecl());
66359878ec8SGabor Horvath }
66459878ec8SGabor Horvath }
66559878ec8SGabor Horvath if (!R)
66659878ec8SGabor Horvath R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
66782923c71SGabor Horvath if (Range)
66882923c71SGabor Horvath R->addRange(*Range);
66982923c71SGabor Horvath R->markInteresting(Sym);
67082923c71SGabor Horvath C.emitReport(std::move(R));
67182923c71SGabor Horvath }
67282923c71SGabor Horvath
registerFuchsiaHandleChecker(CheckerManager & mgr)67382923c71SGabor Horvath void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
67482923c71SGabor Horvath mgr.registerChecker<FuchsiaHandleChecker>();
67582923c71SGabor Horvath }
67682923c71SGabor Horvath
shouldRegisterFuchsiaHandleChecker(const CheckerManager & mgr)677bda3dd0dSKirstóf Umann bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
67882923c71SGabor Horvath return true;
67982923c71SGabor Horvath }
68082923c71SGabor Horvath
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const68182923c71SGabor Horvath void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
68282923c71SGabor Horvath const char *NL, const char *Sep) const {
68382923c71SGabor Horvath
68482923c71SGabor Horvath HStateMapTy StateMap = State->get<HStateMap>();
68582923c71SGabor Horvath
68682923c71SGabor Horvath if (!StateMap.isEmpty()) {
68782923c71SGabor Horvath Out << Sep << "FuchsiaHandleChecker :" << NL;
68882923c71SGabor Horvath for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
68982923c71SGabor Horvath ++I) {
69082923c71SGabor Horvath I.getKey()->dumpToStream(Out);
69182923c71SGabor Horvath Out << " : ";
69282923c71SGabor Horvath I.getData().dump(Out);
69382923c71SGabor Horvath Out << NL;
69482923c71SGabor Horvath }
69582923c71SGabor Horvath }
69682923c71SGabor Horvath }
697