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"
104a1580d7bSKazu Hirata #include <optional>
10582923c71SGabor Horvath
10682923c71SGabor Horvath using namespace clang;
10782923c71SGabor Horvath using namespace ento;
10882923c71SGabor Horvath
10982923c71SGabor Horvath namespace {
11082923c71SGabor Horvath
11182923c71SGabor Horvath static const StringRef HandleTypeName = "zx_handle_t";
11282923c71SGabor Horvath static const StringRef ErrorTypeName = "zx_status_t";
11382923c71SGabor Horvath
11482923c71SGabor Horvath class HandleState {
11582923c71SGabor Horvath private:
1168deaec12SDaniel Hwang enum class Kind { MaybeAllocated, Allocated, Released, Escaped, Unowned } K;
11782923c71SGabor Horvath SymbolRef ErrorSym;
HandleState(Kind K,SymbolRef ErrorSym)11882923c71SGabor Horvath HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
11982923c71SGabor Horvath
12082923c71SGabor Horvath public:
operator ==(const HandleState & Other) const12182923c71SGabor Horvath bool operator==(const HandleState &Other) const {
12282923c71SGabor Horvath return K == Other.K && ErrorSym == Other.ErrorSym;
12382923c71SGabor Horvath }
isAllocated() const12482923c71SGabor Horvath bool isAllocated() const { return K == Kind::Allocated; }
maybeAllocated() const12582923c71SGabor Horvath bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
isReleased() const12682923c71SGabor Horvath bool isReleased() const { return K == Kind::Released; }
isEscaped() const12782923c71SGabor Horvath bool isEscaped() const { return K == Kind::Escaped; }
isUnowned() const1288deaec12SDaniel Hwang bool isUnowned() const { return K == Kind::Unowned; }
12982923c71SGabor Horvath
getMaybeAllocated(SymbolRef ErrorSym)13082923c71SGabor Horvath static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
13182923c71SGabor Horvath return HandleState(Kind::MaybeAllocated, ErrorSym);
13282923c71SGabor Horvath }
getAllocated(ProgramStateRef State,HandleState S)13382923c71SGabor Horvath static HandleState getAllocated(ProgramStateRef State, HandleState S) {
13482923c71SGabor Horvath assert(S.maybeAllocated());
13582923c71SGabor Horvath assert(State->getConstraintManager()
13682923c71SGabor Horvath .isNull(State, S.getErrorSym())
13782923c71SGabor Horvath .isConstrained());
13882923c71SGabor Horvath return HandleState(Kind::Allocated, nullptr);
13982923c71SGabor Horvath }
getReleased()14082923c71SGabor Horvath static HandleState getReleased() {
14182923c71SGabor Horvath return HandleState(Kind::Released, nullptr);
14282923c71SGabor Horvath }
getEscaped()14382923c71SGabor Horvath static HandleState getEscaped() {
14482923c71SGabor Horvath return HandleState(Kind::Escaped, nullptr);
14582923c71SGabor Horvath }
getUnowned()1468deaec12SDaniel Hwang static HandleState getUnowned() {
1478deaec12SDaniel Hwang return HandleState(Kind::Unowned, nullptr);
1488deaec12SDaniel Hwang }
14982923c71SGabor Horvath
getErrorSym() const15082923c71SGabor Horvath SymbolRef getErrorSym() const { return ErrorSym; }
15182923c71SGabor Horvath
Profile(llvm::FoldingSetNodeID & ID) const15282923c71SGabor Horvath void Profile(llvm::FoldingSetNodeID &ID) const {
15382923c71SGabor Horvath ID.AddInteger(static_cast<int>(K));
15482923c71SGabor Horvath ID.AddPointer(ErrorSym);
15582923c71SGabor Horvath }
15682923c71SGabor Horvath
dump(raw_ostream & OS) const15782923c71SGabor Horvath LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
15882923c71SGabor Horvath switch (K) {
15982923c71SGabor Horvath #define CASE(ID) \
16082923c71SGabor Horvath case ID: \
16182923c71SGabor Horvath OS << #ID; \
16282923c71SGabor Horvath break;
16382923c71SGabor Horvath CASE(Kind::MaybeAllocated)
16482923c71SGabor Horvath CASE(Kind::Allocated)
16582923c71SGabor Horvath CASE(Kind::Released)
16682923c71SGabor Horvath CASE(Kind::Escaped)
1678deaec12SDaniel Hwang CASE(Kind::Unowned)
16882923c71SGabor Horvath }
169c98d98baSGabor Horvath if (ErrorSym) {
170c98d98baSGabor Horvath OS << " ErrorSym: ";
171c98d98baSGabor Horvath ErrorSym->dumpToStream(OS);
172c98d98baSGabor Horvath }
17382923c71SGabor Horvath }
17482923c71SGabor Horvath
dump() const17582923c71SGabor Horvath LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
17682923c71SGabor Horvath };
17782923c71SGabor Horvath
hasFuchsiaAttr(const Decl * D)17882923c71SGabor Horvath template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
17982923c71SGabor Horvath return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia";
18082923c71SGabor Horvath }
18182923c71SGabor Horvath
hasFuchsiaUnownedAttr(const Decl * D)1828deaec12SDaniel Hwang template <typename Attr> static bool hasFuchsiaUnownedAttr(const Decl *D) {
1838deaec12SDaniel Hwang return D->hasAttr<Attr>() &&
1848deaec12SDaniel Hwang D->getAttr<Attr>()->getHandleType() == "FuchsiaUnowned";
1858deaec12SDaniel Hwang }
1868deaec12SDaniel Hwang
18782923c71SGabor Horvath class FuchsiaHandleChecker
18882923c71SGabor Horvath : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
18982923c71SGabor Horvath check::PointerEscape, eval::Assume> {
19082923c71SGabor Horvath BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
19182923c71SGabor Horvath /*SuppressOnSink=*/true};
19282923c71SGabor Horvath BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
19382923c71SGabor Horvath "Fuchsia Handle Error"};
19482923c71SGabor Horvath BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
19582923c71SGabor Horvath "Fuchsia Handle Error"};
1968deaec12SDaniel Hwang BugType ReleaseUnownedBugType{
1978deaec12SDaniel Hwang this, "Fuchsia handle release of unowned handle", "Fuchsia Handle Error"};
19882923c71SGabor Horvath
19982923c71SGabor Horvath public:
20082923c71SGabor Horvath void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
20182923c71SGabor Horvath void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
20282923c71SGabor Horvath void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
20382923c71SGabor Horvath ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
20482923c71SGabor Horvath bool Assumption) const;
20582923c71SGabor Horvath ProgramStateRef checkPointerEscape(ProgramStateRef State,
20682923c71SGabor Horvath const InvalidatedSymbols &Escaped,
20782923c71SGabor Horvath const CallEvent *Call,
20882923c71SGabor Horvath PointerEscapeKind Kind) const;
20982923c71SGabor Horvath
21082923c71SGabor Horvath ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
21182923c71SGabor Horvath CheckerContext &C, ExplodedNode *Pred) const;
21282923c71SGabor Horvath
21382923c71SGabor Horvath void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
21482923c71SGabor Horvath CheckerContext &C) const;
21582923c71SGabor Horvath
2168deaec12SDaniel Hwang void reportUnownedRelease(SymbolRef HandleSym, const SourceRange &Range,
2178deaec12SDaniel Hwang CheckerContext &C) const;
2188deaec12SDaniel Hwang
21982923c71SGabor Horvath void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
22082923c71SGabor Horvath CheckerContext &C) const;
22182923c71SGabor Horvath
22282923c71SGabor Horvath void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
22382923c71SGabor Horvath const SourceRange *Range, const BugType &Type,
22482923c71SGabor Horvath StringRef Msg) const;
22582923c71SGabor Horvath
22682923c71SGabor Horvath void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
22782923c71SGabor Horvath const char *Sep) const override;
22882923c71SGabor Horvath };
22982923c71SGabor Horvath } // end anonymous namespace
23082923c71SGabor Horvath
REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap,SymbolRef,HandleState) const23182923c71SGabor Horvath REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
23282923c71SGabor Horvath
23359878ec8SGabor Horvath static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
23459878ec8SGabor Horvath CheckerContext &Ctx) {
23559878ec8SGabor Horvath ProgramStateRef State = N->getState();
23659878ec8SGabor Horvath // When bug type is handle leak, exploded node N does not have state info for
23759878ec8SGabor Horvath // leaking handle. Get the predecessor of N instead.
23859878ec8SGabor Horvath if (!State->get<HStateMap>(Sym))
23959878ec8SGabor Horvath N = N->getFirstPred();
24059878ec8SGabor Horvath
24159878ec8SGabor Horvath const ExplodedNode *Pred = N;
24259878ec8SGabor Horvath while (N) {
24359878ec8SGabor Horvath State = N->getState();
24459878ec8SGabor Horvath if (!State->get<HStateMap>(Sym)) {
24559878ec8SGabor Horvath const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
24659878ec8SGabor Horvath if (HState && (HState->isAllocated() || HState->maybeAllocated()))
24759878ec8SGabor Horvath return N;
24859878ec8SGabor Horvath }
24959878ec8SGabor Horvath Pred = N;
25059878ec8SGabor Horvath N = N->getFirstPred();
25159878ec8SGabor Horvath }
25259878ec8SGabor Horvath return nullptr;
25359878ec8SGabor Horvath }
25459878ec8SGabor Horvath
255914f6c4fSHaowei Wu namespace {
256914f6c4fSHaowei Wu class FuchsiaHandleSymbolVisitor final : public SymbolVisitor {
257914f6c4fSHaowei Wu public:
VisitSymbol(SymbolRef S)258914f6c4fSHaowei Wu bool VisitSymbol(SymbolRef S) override {
259914f6c4fSHaowei Wu if (const auto *HandleType = S->getType()->getAs<TypedefType>())
260914f6c4fSHaowei Wu if (HandleType->getDecl()->getName() == HandleTypeName)
261914f6c4fSHaowei Wu Symbols.push_back(S);
262914f6c4fSHaowei Wu return true;
263914f6c4fSHaowei Wu }
264914f6c4fSHaowei Wu
GetSymbols()265914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> GetSymbols() { return Symbols; }
266914f6c4fSHaowei Wu
267914f6c4fSHaowei Wu private:
268914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Symbols;
269914f6c4fSHaowei Wu };
270914f6c4fSHaowei Wu } // end anonymous namespace
271914f6c4fSHaowei Wu
272914f6c4fSHaowei Wu /// Returns the symbols extracted from the argument or empty vector if it cannot
273914f6c4fSHaowei Wu /// be found. It is unlikely to have over 1024 symbols in one argument.
274914f6c4fSHaowei Wu static SmallVector<SymbolRef, 1024>
getFuchsiaHandleSymbols(QualType QT,SVal Arg,ProgramStateRef State)275914f6c4fSHaowei Wu getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
27682923c71SGabor Horvath int PtrToHandleLevel = 0;
27782923c71SGabor Horvath while (QT->isAnyPointerType() || QT->isReferenceType()) {
27882923c71SGabor Horvath ++PtrToHandleLevel;
27982923c71SGabor Horvath QT = QT->getPointeeType();
28082923c71SGabor Horvath }
281914f6c4fSHaowei Wu if (QT->isStructureType()) {
282914f6c4fSHaowei Wu // If we see a structure, see if there is any handle referenced by the
283914f6c4fSHaowei Wu // structure.
284f1b18a79SBalazs Benics FuchsiaHandleSymbolVisitor Visitor;
285914f6c4fSHaowei Wu State->scanReachableSymbols(Arg, Visitor);
286914f6c4fSHaowei Wu return Visitor.GetSymbols();
287914f6c4fSHaowei Wu }
28882923c71SGabor Horvath if (const auto *HandleType = QT->getAs<TypedefType>()) {
28982923c71SGabor Horvath if (HandleType->getDecl()->getName() != HandleTypeName)
290914f6c4fSHaowei Wu return {};
291914f6c4fSHaowei Wu if (PtrToHandleLevel > 1)
29282923c71SGabor Horvath // Not supported yet.
293914f6c4fSHaowei Wu return {};
29482923c71SGabor Horvath
29582923c71SGabor Horvath if (PtrToHandleLevel == 0) {
296914f6c4fSHaowei Wu SymbolRef Sym = Arg.getAsSymbol();
297914f6c4fSHaowei Wu if (Sym) {
298914f6c4fSHaowei Wu return {Sym};
299914f6c4fSHaowei Wu } else {
300914f6c4fSHaowei Wu return {};
301914f6c4fSHaowei Wu }
30282923c71SGabor Horvath } else {
30382923c71SGabor Horvath assert(PtrToHandleLevel == 1);
3046ad0788cSKazu Hirata if (std::optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
305914f6c4fSHaowei Wu SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
306914f6c4fSHaowei Wu if (Sym) {
307914f6c4fSHaowei Wu return {Sym};
308914f6c4fSHaowei Wu } else {
309914f6c4fSHaowei Wu return {};
31082923c71SGabor Horvath }
31182923c71SGabor Horvath }
312914f6c4fSHaowei Wu }
313914f6c4fSHaowei Wu }
314914f6c4fSHaowei Wu return {};
31582923c71SGabor Horvath }
31682923c71SGabor Horvath
checkPreCall(const CallEvent & Call,CheckerContext & C) const31782923c71SGabor Horvath void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
31882923c71SGabor Horvath CheckerContext &C) const {
31982923c71SGabor Horvath ProgramStateRef State = C.getState();
32082923c71SGabor Horvath const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
32182923c71SGabor Horvath if (!FuncDecl) {
32282923c71SGabor Horvath // Unknown call, escape by value handles. They are not covered by
32382923c71SGabor Horvath // PointerEscape callback.
32482923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
32582923c71SGabor Horvath if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
32682923c71SGabor Horvath State = State->set<HStateMap>(Handle, HandleState::getEscaped());
32782923c71SGabor Horvath }
32882923c71SGabor Horvath C.addTransition(State);
32982923c71SGabor Horvath return;
33082923c71SGabor Horvath }
33182923c71SGabor Horvath
33282923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
33382923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
33482923c71SGabor Horvath break;
33582923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
336914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
337914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
33882923c71SGabor Horvath
33982923c71SGabor Horvath // Handled in checkPostCall.
34082923c71SGabor Horvath if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
34182923c71SGabor Horvath hasFuchsiaAttr<AcquireHandleAttr>(PVD))
34282923c71SGabor Horvath continue;
34382923c71SGabor Horvath
344914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
34582923c71SGabor Horvath const HandleState *HState = State->get<HStateMap>(Handle);
34682923c71SGabor Horvath if (!HState || HState->isEscaped())
34782923c71SGabor Horvath continue;
34882923c71SGabor Horvath
349914f6c4fSHaowei Wu if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
350914f6c4fSHaowei Wu PVD->getType()->isIntegerType()) {
35182923c71SGabor Horvath if (HState->isReleased()) {
35282923c71SGabor Horvath reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
35382923c71SGabor Horvath return;
35482923c71SGabor Horvath }
35582923c71SGabor Horvath }
35682923c71SGabor Horvath }
357914f6c4fSHaowei Wu }
35882923c71SGabor Horvath C.addTransition(State);
35982923c71SGabor Horvath }
36082923c71SGabor Horvath
checkPostCall(const CallEvent & Call,CheckerContext & C) const36182923c71SGabor Horvath void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
36282923c71SGabor Horvath CheckerContext &C) const {
36382923c71SGabor Horvath const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
36482923c71SGabor Horvath if (!FuncDecl)
36582923c71SGabor Horvath return;
36682923c71SGabor Horvath
3673ce78f54SYu Shan // If we analyzed the function body, then ignore the annotations.
3683ce78f54SYu Shan if (C.wasInlined)
3693ce78f54SYu Shan return;
3703ce78f54SYu Shan
37182923c71SGabor Horvath ProgramStateRef State = C.getState();
37282923c71SGabor Horvath
37359878ec8SGabor Horvath std::vector<std::function<std::string(BugReport & BR)>> Notes;
37482923c71SGabor Horvath SymbolRef ResultSymbol = nullptr;
37582923c71SGabor Horvath if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
37682923c71SGabor Horvath if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
37782923c71SGabor Horvath ResultSymbol = Call.getReturnValue().getAsSymbol();
37882923c71SGabor Horvath
37982923c71SGabor Horvath // Function returns an open handle.
38082923c71SGabor Horvath if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
38182923c71SGabor Horvath SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3825911268eSGabor Horvath Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3835911268eSGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
384*01b88dd6STakuya Shimizu if (PathBR->getInterestingnessKind(RetSym)) {
3855911268eSGabor Horvath std::string SBuf;
3865911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
38719701458SBruno Ricci OS << "Function '" << FuncDecl->getDeclName()
3885911268eSGabor Horvath << "' returns an open handle";
389715c72b4SLogan Smith return SBuf;
3905911268eSGabor Horvath } else
3915911268eSGabor Horvath return "";
3925911268eSGabor Horvath });
39382923c71SGabor Horvath State =
39482923c71SGabor Horvath State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
3958deaec12SDaniel Hwang } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(FuncDecl)) {
3968deaec12SDaniel Hwang // Function returns an unowned handle
3978deaec12SDaniel Hwang SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
3988deaec12SDaniel Hwang Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
3998deaec12SDaniel Hwang auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
400*01b88dd6STakuya Shimizu if (PathBR->getInterestingnessKind(RetSym)) {
4018deaec12SDaniel Hwang std::string SBuf;
4028deaec12SDaniel Hwang llvm::raw_string_ostream OS(SBuf);
4038deaec12SDaniel Hwang OS << "Function '" << FuncDecl->getDeclName()
4048deaec12SDaniel Hwang << "' returns an unowned handle";
405715c72b4SLogan Smith return SBuf;
4068deaec12SDaniel Hwang } else
4078deaec12SDaniel Hwang return "";
4088deaec12SDaniel Hwang });
4098deaec12SDaniel Hwang State = State->set<HStateMap>(RetSym, HandleState::getUnowned());
41082923c71SGabor Horvath }
41182923c71SGabor Horvath
41282923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) {
41382923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
41482923c71SGabor Horvath break;
41582923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
4165911268eSGabor Horvath unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
417914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
418914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State);
41982923c71SGabor Horvath
420914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
42182923c71SGabor Horvath const HandleState *HState = State->get<HStateMap>(Handle);
42282923c71SGabor Horvath if (HState && HState->isEscaped())
42382923c71SGabor Horvath continue;
42482923c71SGabor Horvath if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
42582923c71SGabor Horvath if (HState && HState->isReleased()) {
42682923c71SGabor Horvath reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
42782923c71SGabor Horvath return;
4288deaec12SDaniel Hwang } else if (HState && HState->isUnowned()) {
4298deaec12SDaniel Hwang reportUnownedRelease(Handle, Call.getArgSourceRange(Arg), C);
4308deaec12SDaniel Hwang return;
43159878ec8SGabor Horvath } else {
4325911268eSGabor Horvath Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
43359878ec8SGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
434*01b88dd6STakuya Shimizu if (PathBR->getInterestingnessKind(Handle)) {
4355911268eSGabor Horvath std::string SBuf;
4365911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
4375911268eSGabor Horvath OS << "Handle released through " << ParamDiagIdx
4385911268eSGabor Horvath << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
439715c72b4SLogan Smith return SBuf;
44082923c71SGabor Horvath } else
44159878ec8SGabor Horvath return "";
44259878ec8SGabor Horvath });
44382923c71SGabor Horvath State = State->set<HStateMap>(Handle, HandleState::getReleased());
44459878ec8SGabor Horvath }
44582923c71SGabor Horvath } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
4465911268eSGabor Horvath Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
44759878ec8SGabor Horvath auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
448*01b88dd6STakuya Shimizu if (PathBR->getInterestingnessKind(Handle)) {
4495911268eSGabor Horvath std::string SBuf;
4505911268eSGabor Horvath llvm::raw_string_ostream OS(SBuf);
4515911268eSGabor Horvath OS << "Handle allocated through " << ParamDiagIdx
4525911268eSGabor Horvath << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
453715c72b4SLogan Smith return SBuf;
45459878ec8SGabor Horvath } else
45559878ec8SGabor Horvath return "";
45659878ec8SGabor Horvath });
45782923c71SGabor Horvath State = State->set<HStateMap>(
45882923c71SGabor Horvath Handle, HandleState::getMaybeAllocated(ResultSymbol));
4598deaec12SDaniel Hwang } else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
4608deaec12SDaniel Hwang Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
4618deaec12SDaniel Hwang auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
462*01b88dd6STakuya Shimizu if (PathBR->getInterestingnessKind(Handle)) {
4638deaec12SDaniel Hwang std::string SBuf;
4648deaec12SDaniel Hwang llvm::raw_string_ostream OS(SBuf);
4658deaec12SDaniel Hwang OS << "Unowned handle allocated through " << ParamDiagIdx
4668deaec12SDaniel Hwang << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
467715c72b4SLogan Smith return SBuf;
4688deaec12SDaniel Hwang } else
4698deaec12SDaniel Hwang return "";
4708deaec12SDaniel Hwang });
4718deaec12SDaniel Hwang State = State->set<HStateMap>(Handle, HandleState::getUnowned());
4723ce78f54SYu Shan } else if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
4733ce78f54SYu Shan PVD->getType()->isIntegerType()) {
4743ce78f54SYu Shan // Working around integer by-value escapes.
4753ce78f54SYu Shan // The by-value escape would not be captured in checkPointerEscape.
4763ce78f54SYu Shan // If the function was not analyzed (otherwise wasInlined should be
4773ce78f54SYu Shan // true) and there is no annotation on the handle, we assume the handle
4783ce78f54SYu Shan // is escaped.
4793ce78f54SYu Shan State = State->set<HStateMap>(Handle, HandleState::getEscaped());
48082923c71SGabor Horvath }
48182923c71SGabor Horvath }
482914f6c4fSHaowei Wu }
48359878ec8SGabor Horvath const NoteTag *T = nullptr;
48459878ec8SGabor Horvath if (!Notes.empty()) {
48520a3d64cSAdam Balogh T = C.getNoteTag([this, Notes{std::move(Notes)}](
48620a3d64cSAdam Balogh PathSensitiveBugReport &BR) -> std::string {
48759878ec8SGabor Horvath if (&BR.getBugType() != &UseAfterReleaseBugType &&
48859878ec8SGabor Horvath &BR.getBugType() != &LeakBugType &&
4898deaec12SDaniel Hwang &BR.getBugType() != &DoubleReleaseBugType &&
4908deaec12SDaniel Hwang &BR.getBugType() != &ReleaseUnownedBugType)
49159878ec8SGabor Horvath return "";
49259878ec8SGabor Horvath for (auto &Note : Notes) {
49359878ec8SGabor Horvath std::string Text = Note(BR);
49459878ec8SGabor Horvath if (!Text.empty())
49559878ec8SGabor Horvath return Text;
49659878ec8SGabor Horvath }
49759878ec8SGabor Horvath return "";
49859878ec8SGabor Horvath });
49959878ec8SGabor Horvath }
50059878ec8SGabor Horvath C.addTransition(State, T);
50182923c71SGabor Horvath }
50282923c71SGabor Horvath
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const50382923c71SGabor Horvath void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
50482923c71SGabor Horvath CheckerContext &C) const {
50582923c71SGabor Horvath ProgramStateRef State = C.getState();
50682923c71SGabor Horvath SmallVector<SymbolRef, 2> LeakedSyms;
50782923c71SGabor Horvath HStateMapTy TrackedHandles = State->get<HStateMap>();
50882923c71SGabor Horvath for (auto &CurItem : TrackedHandles) {
509c98d98baSGabor Horvath SymbolRef ErrorSym = CurItem.second.getErrorSym();
510c98d98baSGabor Horvath // Keeping zombie handle symbols. In case the error symbol is dying later
511c98d98baSGabor Horvath // than the handle symbol we might produce spurious leak warnings (in case
512c98d98baSGabor Horvath // we find out later from the status code that the handle allocation failed
513c98d98baSGabor Horvath // in the first place).
514c98d98baSGabor Horvath if (!SymReaper.isDead(CurItem.first) ||
515c98d98baSGabor Horvath (ErrorSym && !SymReaper.isDead(ErrorSym)))
51682923c71SGabor Horvath continue;
51782923c71SGabor Horvath if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated())
51882923c71SGabor Horvath LeakedSyms.push_back(CurItem.first);
51982923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
52082923c71SGabor Horvath }
52182923c71SGabor Horvath
52282923c71SGabor Horvath ExplodedNode *N = C.getPredecessor();
52382923c71SGabor Horvath if (!LeakedSyms.empty())
52482923c71SGabor Horvath N = reportLeaks(LeakedSyms, C, N);
52582923c71SGabor Horvath
52682923c71SGabor Horvath C.addTransition(State, N);
52782923c71SGabor Horvath }
52882923c71SGabor Horvath
52982923c71SGabor Horvath // Acquiring a handle is not always successful. In Fuchsia most functions
53082923c71SGabor Horvath // return a status code that determines the status of the handle.
53182923c71SGabor Horvath // When we split the path based on this status code we know that on one
53282923c71SGabor Horvath // path we do have the handle and on the other path the acquire failed.
53382923c71SGabor Horvath // This method helps avoiding false positive leak warnings on paths where
53482923c71SGabor Horvath // the function failed.
53582923c71SGabor Horvath // Moreover, when a handle is known to be zero (the invalid handle),
53682923c71SGabor Horvath // we no longer can follow the symbol on the path, becaue the constant
53782923c71SGabor Horvath // zero will be used instead of the symbol. We also do not need to release
53882923c71SGabor Horvath // an invalid handle, so we remove the corresponding symbol from the state.
evalAssume(ProgramStateRef State,SVal Cond,bool Assumption) const53982923c71SGabor Horvath ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
54082923c71SGabor Horvath SVal Cond,
54182923c71SGabor Horvath bool Assumption) const {
54259878ec8SGabor Horvath // TODO: add notes about successes/fails for APIs.
54382923c71SGabor Horvath ConstraintManager &Cmr = State->getConstraintManager();
54482923c71SGabor Horvath HStateMapTy TrackedHandles = State->get<HStateMap>();
54582923c71SGabor Horvath for (auto &CurItem : TrackedHandles) {
54682923c71SGabor Horvath ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
54782923c71SGabor Horvath if (HandleVal.isConstrainedTrue()) {
54882923c71SGabor Horvath // The handle is invalid. We can no longer follow the symbol on this path.
54982923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
55082923c71SGabor Horvath }
55182923c71SGabor Horvath SymbolRef ErrorSym = CurItem.second.getErrorSym();
55282923c71SGabor Horvath if (!ErrorSym)
55382923c71SGabor Horvath continue;
55482923c71SGabor Horvath ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
55582923c71SGabor Horvath if (ErrorVal.isConstrainedTrue()) {
55682923c71SGabor Horvath // Allocation succeeded.
55782923c71SGabor Horvath if (CurItem.second.maybeAllocated())
55882923c71SGabor Horvath State = State->set<HStateMap>(
55982923c71SGabor Horvath CurItem.first, HandleState::getAllocated(State, CurItem.second));
56082923c71SGabor Horvath } else if (ErrorVal.isConstrainedFalse()) {
56182923c71SGabor Horvath // Allocation failed.
56282923c71SGabor Horvath if (CurItem.second.maybeAllocated())
56382923c71SGabor Horvath State = State->remove<HStateMap>(CurItem.first);
56482923c71SGabor Horvath }
56582923c71SGabor Horvath }
56682923c71SGabor Horvath return State;
56782923c71SGabor Horvath }
56882923c71SGabor Horvath
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const56982923c71SGabor Horvath ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
57082923c71SGabor Horvath ProgramStateRef State, const InvalidatedSymbols &Escaped,
57182923c71SGabor Horvath const CallEvent *Call, PointerEscapeKind Kind) const {
57282923c71SGabor Horvath const FunctionDecl *FuncDecl =
57382923c71SGabor Horvath Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr;
57482923c71SGabor Horvath
57582923c71SGabor Horvath llvm::DenseSet<SymbolRef> UnEscaped;
57682923c71SGabor Horvath // Not all calls should escape our symbols.
57782923c71SGabor Horvath if (FuncDecl &&
57882923c71SGabor Horvath (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall ||
57982923c71SGabor Horvath Kind == PSK_EscapeOutParameters)) {
58082923c71SGabor Horvath for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) {
58182923c71SGabor Horvath if (Arg >= FuncDecl->getNumParams())
58282923c71SGabor Horvath break;
58382923c71SGabor Horvath const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
584914f6c4fSHaowei Wu SmallVector<SymbolRef, 1024> Handles =
585914f6c4fSHaowei Wu getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State);
586914f6c4fSHaowei Wu for (SymbolRef Handle : Handles) {
58782923c71SGabor Horvath if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
588914f6c4fSHaowei Wu hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
58982923c71SGabor Horvath UnEscaped.insert(Handle);
59082923c71SGabor Horvath }
59182923c71SGabor Horvath }
592914f6c4fSHaowei Wu }
593914f6c4fSHaowei Wu }
59482923c71SGabor Horvath
59582923c71SGabor Horvath // For out params, we have to deal with derived symbols. See
59682923c71SGabor Horvath // MacOSKeychainAPIChecker for details.
59782923c71SGabor Horvath for (auto I : State->get<HStateMap>()) {
59882923c71SGabor Horvath if (Escaped.count(I.first) && !UnEscaped.count(I.first))
59982923c71SGabor Horvath State = State->set<HStateMap>(I.first, HandleState::getEscaped());
60082923c71SGabor Horvath if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
60182923c71SGabor Horvath auto ParentSym = SD->getParentSymbol();
60282923c71SGabor Horvath if (Escaped.count(ParentSym))
60382923c71SGabor Horvath State = State->set<HStateMap>(I.first, HandleState::getEscaped());
60482923c71SGabor Horvath }
60582923c71SGabor Horvath }
60682923c71SGabor Horvath
60782923c71SGabor Horvath return State;
60882923c71SGabor Horvath }
60982923c71SGabor Horvath
61082923c71SGabor Horvath ExplodedNode *
reportLeaks(ArrayRef<SymbolRef> LeakedHandles,CheckerContext & C,ExplodedNode * Pred) const61182923c71SGabor Horvath FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
61282923c71SGabor Horvath CheckerContext &C, ExplodedNode *Pred) const {
61382923c71SGabor Horvath ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
61482923c71SGabor Horvath for (SymbolRef LeakedHandle : LeakedHandles) {
61582923c71SGabor Horvath reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
61682923c71SGabor Horvath "Potential leak of handle");
61782923c71SGabor Horvath }
61882923c71SGabor Horvath return ErrNode;
61982923c71SGabor Horvath }
62082923c71SGabor Horvath
reportDoubleRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const62182923c71SGabor Horvath void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
62282923c71SGabor Horvath const SourceRange &Range,
62382923c71SGabor Horvath CheckerContext &C) const {
62482923c71SGabor Horvath ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
62582923c71SGabor Horvath reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
62682923c71SGabor Horvath "Releasing a previously released handle");
62782923c71SGabor Horvath }
62882923c71SGabor Horvath
reportUnownedRelease(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const6298deaec12SDaniel Hwang void FuchsiaHandleChecker::reportUnownedRelease(SymbolRef HandleSym,
6308deaec12SDaniel Hwang const SourceRange &Range,
6318deaec12SDaniel Hwang CheckerContext &C) const {
6328deaec12SDaniel Hwang ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
6338deaec12SDaniel Hwang reportBug(HandleSym, ErrNode, C, &Range, ReleaseUnownedBugType,
6348deaec12SDaniel Hwang "Releasing an unowned handle");
6358deaec12SDaniel Hwang }
6368deaec12SDaniel Hwang
reportUseAfterFree(SymbolRef HandleSym,const SourceRange & Range,CheckerContext & C) const63782923c71SGabor Horvath void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
63882923c71SGabor Horvath const SourceRange &Range,
63982923c71SGabor Horvath CheckerContext &C) const {
64082923c71SGabor Horvath ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
64182923c71SGabor Horvath reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
64282923c71SGabor Horvath "Using a previously released handle");
64382923c71SGabor Horvath }
64482923c71SGabor Horvath
reportBug(SymbolRef Sym,ExplodedNode * ErrorNode,CheckerContext & C,const SourceRange * Range,const BugType & Type,StringRef Msg) const64582923c71SGabor Horvath void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
64682923c71SGabor Horvath CheckerContext &C,
64782923c71SGabor Horvath const SourceRange *Range,
64882923c71SGabor Horvath const BugType &Type, StringRef Msg) const {
64982923c71SGabor Horvath if (!ErrorNode)
65082923c71SGabor Horvath return;
65182923c71SGabor Horvath
65259878ec8SGabor Horvath std::unique_ptr<PathSensitiveBugReport> R;
65359878ec8SGabor Horvath if (Type.isSuppressOnSink()) {
65459878ec8SGabor Horvath const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
65559878ec8SGabor Horvath if (AcquireNode) {
656e62b2fc4SElizabeth Andrews const Stmt *S = AcquireNode->getStmtForDiagnostics();
657e62b2fc4SElizabeth Andrews assert(S && "Statement cannot be null.");
65859878ec8SGabor Horvath PathDiagnosticLocation LocUsedForUniqueing =
65959878ec8SGabor Horvath PathDiagnosticLocation::createBegin(
660e62b2fc4SElizabeth Andrews S, C.getSourceManager(), AcquireNode->getLocationContext());
66159878ec8SGabor Horvath
66259878ec8SGabor Horvath R = std::make_unique<PathSensitiveBugReport>(
66359878ec8SGabor Horvath Type, Msg, ErrorNode, LocUsedForUniqueing,
66459878ec8SGabor Horvath AcquireNode->getLocationContext()->getDecl());
66559878ec8SGabor Horvath }
66659878ec8SGabor Horvath }
66759878ec8SGabor Horvath if (!R)
66859878ec8SGabor Horvath R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
66982923c71SGabor Horvath if (Range)
67082923c71SGabor Horvath R->addRange(*Range);
67182923c71SGabor Horvath R->markInteresting(Sym);
67282923c71SGabor Horvath C.emitReport(std::move(R));
67382923c71SGabor Horvath }
67482923c71SGabor Horvath
registerFuchsiaHandleChecker(CheckerManager & mgr)67582923c71SGabor Horvath void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
67682923c71SGabor Horvath mgr.registerChecker<FuchsiaHandleChecker>();
67782923c71SGabor Horvath }
67882923c71SGabor Horvath
shouldRegisterFuchsiaHandleChecker(const CheckerManager & mgr)679bda3dd0dSKirstóf Umann bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
68082923c71SGabor Horvath return true;
68182923c71SGabor Horvath }
68282923c71SGabor Horvath
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const68382923c71SGabor Horvath void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
68482923c71SGabor Horvath const char *NL, const char *Sep) const {
68582923c71SGabor Horvath
68682923c71SGabor Horvath HStateMapTy StateMap = State->get<HStateMap>();
68782923c71SGabor Horvath
68882923c71SGabor Horvath if (!StateMap.isEmpty()) {
68982923c71SGabor Horvath Out << Sep << "FuchsiaHandleChecker :" << NL;
6905c23e27bSBalazs Benics for (const auto &[Sym, HandleState] : StateMap) {
6915c23e27bSBalazs Benics Sym->dumpToStream(Out);
69282923c71SGabor Horvath Out << " : ";
6935c23e27bSBalazs Benics HandleState.dump(Out);
69482923c71SGabor Horvath Out << NL;
69582923c71SGabor Horvath }
69682923c71SGabor Horvath }
69782923c71SGabor Horvath }
698