Coverage Report

Created: 2020-10-24 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This checker checks if the handle of Fuchsia is properly used according to
10
// following rules.
11
//   - If a handle is acquired, it should be released before execution
12
//        ends.
13
//   - If a handle is released, it should not be released again.
14
//   - If a handle is released, it should not be used for other purposes
15
//        such as I/O.
16
//
17
// In this checker, each tracked handle is associated with a state. When the
18
// handle variable is passed to different function calls or syscalls, its state
19
// changes. The state changes can be generally represented by following ASCII
20
// Art:
21
//
22
//
23
//                              +-+---------v-+         +------------+
24
//       acquire_func succeeded |             | Escape  |            |
25
//            +----------------->  Allocated  +--------->  Escaped   <--+
26
//            |                 |             |         |            |  |
27
//            |                 +-----+------++         +------------+  |
28
//            |                       |      |                          |
29
//            |         release_func  |      +--+                       |
30
//            |                       |         | handle  +--------+    |
31
//            |                       |         | dies    |        |    |
32
//            |                  +----v-----+   +---------> Leaked |    |
33
//            |                  |          |             |(REPORT)|    |
34
// +----------+--+               | Released | Escape      +--------+    |
35
// |             |               |          +---------------------------+
36
// | Not tracked <--+            +----+---+-+
37
// |             |  |                 |   |        As argument by value
38
// +------+------+  |    release_func |   +------+ in function call
39
//        |         |                 |          | or by reference in
40
//        |         |                 |          | use_func call
41
//        +---------+            +----v-----+    |     +-----------+
42
//        acquire_func failed    | Double   |    +-----> Use after |
43
//                               | released |          | released  |
44
//                               | (REPORT) |          | (REPORT)  |
45
//                               +----------+          +-----------+
46
//
47
// acquire_func represents the functions or syscalls that may acquire a handle.
48
// release_func represents the functions or syscalls that may release a handle.
49
// use_func represents the functions or syscall that requires an open handle.
50
//
51
// If a tracked handle dies in "Released" or "Not Tracked" state, we assume it
52
// is properly used. Otherwise a bug and will be reported.
53
//
54
// Note that, the analyzer does not always know for sure if a function failed
55
// or succeeded. In those cases we use the state MaybeAllocated.
56
// Thus, the diagramm above captures the intent, not implementation details.
57
//
58
// Due to the fact that the number of handle related syscalls in Fuchsia
59
// is large, we adopt the annotation attributes to descript syscalls'
60
// operations(acquire/release/use) on handles instead of hardcoding
61
// everything in the checker.
62
//
63
// We use following annotation attributes for handle related syscalls or
64
// functions:
65
//  1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired
66
//  2. __attribute__((release_handle("Fuchsia"))) |handle will be released
67
//  3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to
68
//     escaped state, it also needs to be open.
69
//
70
// For example, an annotated syscall:
71
//   zx_status_t zx_channel_create(
72
//   uint32_t options,
73
//   zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) ,
74
//   zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia"))));
75
// denotes a syscall which will acquire two handles and save them to 'out0' and
76
// 'out1' when succeeded.
77
//
78
//===----------------------------------------------------------------------===//
79
80
#include "clang/AST/Attr.h"
81
#include "clang/AST/Decl.h"
82
#include "clang/AST/Type.h"
83
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
84
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
85
#include "clang/StaticAnalyzer/Core/Checker.h"
86
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
87
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
88
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
89
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
90
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
91
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
92
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
93
#include "llvm/ADT/StringExtras.h"
94
95
using namespace clang;
96
using namespace ento;
97
98
namespace {
99
100
static const StringRef HandleTypeName = "zx_handle_t";
101
static const StringRef ErrorTypeName = "zx_status_t";
102
103
class HandleState {
104
private:
105
  enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K;
106
  SymbolRef ErrorSym;
107
131
  HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {}
108
109
public:
110
24
  bool operator==(const HandleState &Other) const {
111
24
    return K == Other.K && ErrorSym == Other.ErrorSym;
112
24
  }
113
83
  bool isAllocated() const { return K == Kind::Allocated; }
114
148
  bool maybeAllocated() const { return K == Kind::MaybeAllocated; }
115
49
  bool isReleased() const { return K == Kind::Released; }
116
64
  bool isEscaped() const { return K == Kind::Escaped; }
117
118
56
  static HandleState getMaybeAllocated(SymbolRef ErrorSym) {
119
56
    return HandleState(Kind::MaybeAllocated, ErrorSym);
120
56
  }
121
24
  static HandleState getAllocated(ProgramStateRef State, HandleState S) {
122
24
    assert(S.maybeAllocated());
123
24
    assert(State->getConstraintManager()
124
24
               .isNull(State, S.getErrorSym())
125
24
               .isConstrained());
126
24
    return HandleState(Kind::Allocated, nullptr);
127
24
  }
128
35
  static HandleState getReleased() {
129
35
    return HandleState(Kind::Released, nullptr);
130
35
  }
131
16
  static HandleState getEscaped() {
132
16
    return HandleState(Kind::Escaped, nullptr);
133
16
  }
134
135
656
  SymbolRef getErrorSym() const { return ErrorSym; }
136
137
213
  void Profile(llvm::FoldingSetNodeID &ID) const {
138
213
    ID.AddInteger(static_cast<int>(K));
139
213
    ID.AddPointer(ErrorSym);
140
213
  }
141
142
0
  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
143
0
    switch (K) {
144
0
#define CASE(ID)                                                               \
145
0
  case ID:                                                                     \
146
0
    OS << #ID;                                                                 \
147
0
    break;
148
0
      CASE(Kind::MaybeAllocated)
149
0
      CASE(Kind::Allocated)
150
0
      CASE(Kind::Released)
151
0
      CASE(Kind::Escaped)
152
0
    }
153
0
    if (ErrorSym) {
154
0
      OS << " ErrorSym: ";
155
0
      ErrorSym->dumpToStream(OS);
156
0
    }
157
0
  }
158
159
0
  LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
160
};
161
162
537
template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
163
537
  return D->hasAttr<Attr>() && 
D->getAttr<Attr>()->getHandleType() == "Fuchsia"206
;
164
537
}
FuchsiaHandleChecker.cpp:bool (anonymous namespace)::hasFuchsiaAttr<clang::AcquireHandleAttr>(clang::Decl const*)
Line
Count
Source
162
187
template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
163
187
  return D->hasAttr<Attr>() && 
D->getAttr<Attr>()->getHandleType() == "Fuchsia"62
;
164
187
}
FuchsiaHandleChecker.cpp:bool (anonymous namespace)::hasFuchsiaAttr<clang::ReleaseHandleAttr>(clang::Decl const*)
Line
Count
Source
162
236
template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
163
236
  return D->hasAttr<Attr>() && 
D->getAttr<Attr>()->getHandleType() == "Fuchsia"112
;
164
236
}
FuchsiaHandleChecker.cpp:bool (anonymous namespace)::hasFuchsiaAttr<clang::UseHandleAttr>(clang::Decl const*)
Line
Count
Source
162
114
template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) {
163
114
  return D->hasAttr<Attr>() && 
D->getAttr<Attr>()->getHandleType() == "Fuchsia"32
;
164
114
}
165
166
class FuchsiaHandleChecker
167
    : public Checker<check::PostCall, check::PreCall, check::DeadSymbols,
168
                     check::PointerEscape, eval::Assume> {
169
  BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error",
170
                      /*SuppressOnSink=*/true};
171
  BugType DoubleReleaseBugType{this, "Fuchsia handle double release",
172
                               "Fuchsia Handle Error"};
173
  BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release",
174
                                 "Fuchsia Handle Error"};
175
176
public:
177
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
178
  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
179
  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
180
  ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
181
                             bool Assumption) const;
182
  ProgramStateRef checkPointerEscape(ProgramStateRef State,
183
                                     const InvalidatedSymbols &Escaped,
184
                                     const CallEvent *Call,
185
                                     PointerEscapeKind Kind) const;
186
187
  ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
188
                            CheckerContext &C, ExplodedNode *Pred) const;
189
190
  void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
191
                           CheckerContext &C) const;
192
193
  void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
194
                          CheckerContext &C) const;
195
196
  void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C,
197
                 const SourceRange *Range, const BugType &Type,
198
                 StringRef Msg) const;
199
200
  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
201
                  const char *Sep) const override;
202
};
203
} // end anonymous namespace
204
205
REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
206
207
static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym,
208
13
                                          CheckerContext &Ctx) {
209
13
  ProgramStateRef State = N->getState();
210
  // When bug type is handle leak, exploded node N does not have state info for
211
  // leaking handle. Get the predecessor of N instead.
212
13
  if (!State->get<HStateMap>(Sym))
213
0
    N = N->getFirstPred();
214
215
13
  const ExplodedNode *Pred = N;
216
309
  while (N) {
217
309
    State = N->getState();
218
309
    if (!State->get<HStateMap>(Sym)) {
219
13
      const HandleState *HState = Pred->getState()->get<HStateMap>(Sym);
220
13
      if (HState && (HState->isAllocated() || HState->maybeAllocated()))
221
13
        return N;
222
296
    }
223
296
    Pred = N;
224
296
    N = N->getFirstPred();
225
296
  }
226
0
  return nullptr;
227
13
}
228
229
/// Returns the symbols extracted from the argument or null if it cannot be
230
/// found.
231
static SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg,
232
386
                                        ProgramStateRef State) {
233
386
  int PtrToHandleLevel = 0;
234
540
  while (QT->isAnyPointerType() || 
QT->isReferenceType()388
) {
235
154
    ++PtrToHandleLevel;
236
154
    QT = QT->getPointeeType();
237
154
  }
238
386
  if (const auto *HandleType = QT->getAs<TypedefType>()) {
239
375
    if (HandleType->getDecl()->getName() != HandleTypeName)
240
71
      return nullptr;
241
304
    if (PtrToHandleLevel > 1) {
242
      // Not supported yet.
243
0
      return nullptr;
244
0
    }
245
246
304
    if (PtrToHandleLevel == 0) {
247
155
      return Arg.getAsSymbol();
248
149
    } else {
249
149
      assert(PtrToHandleLevel == 1);
250
149
      if (Optional<Loc> ArgLoc = Arg.getAs<Loc>())
251
149
        return State->getSVal(*ArgLoc).getAsSymbol();
252
11
    }
253
304
  }
254
11
  return nullptr;
255
11
}
256
257
void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call,
258
104
                                        CheckerContext &C) const {
259
104
  ProgramStateRef State = C.getState();
260
104
  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
261
104
  if (!FuncDecl) {
262
    // Unknown call, escape by value handles. They are not covered by
263
    // PointerEscape callback.
264
2
    for (unsigned Arg = 0; Arg < Call.getNumArgs(); 
++Arg1
) {
265
1
      if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol())
266
1
        State = State->set<HStateMap>(Handle, HandleState::getEscaped());
267
1
    }
268
1
    C.addTransition(State);
269
1
    return;
270
1
  }
271
272
242
  
for (unsigned Arg = 0; 103
Arg < Call.getNumArgs();
++Arg139
) {
273
142
    if (Arg >= FuncDecl->getNumParams())
274
1
      break;
275
141
    const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
276
141
    SymbolRef Handle =
277
141
        getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
278
141
    if (!Handle)
279
81
      continue;
280
281
    // Handled in checkPostCall.
282
60
    if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) ||
283
22
        hasFuchsiaAttr<AcquireHandleAttr>(PVD))
284
44
      continue;
285
286
16
    const HandleState *HState = State->get<HStateMap>(Handle);
287
16
    if (!HState || HState->isEscaped())
288
1
      continue;
289
290
15
    if (hasFuchsiaAttr<UseHandleAttr>(PVD) || 
PVD->getType()->isIntegerType()3
) {
291
14
      if (HState->isReleased()) {
292
2
        reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C);
293
2
        return;
294
2
      }
295
13
    }
296
13
    if (!hasFuchsiaAttr<UseHandleAttr>(PVD) &&
297
3
        PVD->getType()->isIntegerType()) {
298
      // Working around integer by-value escapes.
299
2
      State = State->set<HStateMap>(Handle, HandleState::getEscaped());
300
2
    }
301
13
  }
302
101
  C.addTransition(State);
303
101
}
304
305
void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
306
102
                                         CheckerContext &C) const {
307
102
  const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
308
102
  if (!FuncDecl)
309
1
    return;
310
311
101
  ProgramStateRef State = C.getState();
312
313
101
  std::vector<std::function<std::string(BugReport & BR)>> Notes;
314
101
  SymbolRef ResultSymbol = nullptr;
315
101
  if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>())
316
66
    if (TypeDefTy->getDecl()->getName() == ErrorTypeName)
317
64
      ResultSymbol = Call.getReturnValue().getAsSymbol();
318
319
  // Function returns an open handle.
320
101
  if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) {
321
2
    SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
322
1
    Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
323
1
      auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
324
1
      if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
325
1
        std::string SBuf;
326
1
        llvm::raw_string_ostream OS(SBuf);
327
1
        OS << "Function '" << FuncDecl->getDeclName()
328
1
           << "' returns an open handle";
329
1
        return OS.str();
330
1
      } else
331
0
        return "";
332
1
    });
333
2
    State =
334
2
        State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr));
335
2
  }
336
337
237
  for (unsigned Arg = 0; Arg < Call.getNumArgs(); 
++Arg136
) {
338
138
    if (Arg >= FuncDecl->getNumParams())
339
1
      break;
340
137
    const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
341
137
    unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1;
342
137
    SymbolRef Handle =
343
137
        getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State);
344
137
    if (!Handle)
345
33
      continue;
346
347
104
    const HandleState *HState = State->get<HStateMap>(Handle);
348
104
    if (HState && 
HState->isEscaped()48
)
349
4
      continue;
350
100
    if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) {
351
36
      if (HState && 
HState->isReleased()35
) {
352
1
        reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C);
353
1
        return;
354
35
      } else {
355
4
        Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
356
4
          auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
357
4
          if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
358
3
            std::string SBuf;
359
3
            llvm::raw_string_ostream OS(SBuf);
360
3
            OS << "Handle released through " << ParamDiagIdx
361
3
               << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
362
3
            return OS.str();
363
3
          } else
364
1
            return "";
365
4
        });
366
35
        State = State->set<HStateMap>(Handle, HandleState::getReleased());
367
35
      }
368
64
    } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
369
7
      Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
370
7
        auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
371
7
        if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
372
6
          std::string SBuf;
373
6
          llvm::raw_string_ostream OS(SBuf);
374
6
          OS << "Handle allocated through " << ParamDiagIdx
375
6
             << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter";
376
6
          return OS.str();
377
6
        } else
378
1
          return "";
379
7
      });
380
54
      State = State->set<HStateMap>(
381
54
          Handle, HandleState::getMaybeAllocated(ResultSymbol));
382
54
    }
383
100
  }
384
100
  const NoteTag *T = nullptr;
385
100
  if (!Notes.empty()) {
386
63
    T = C.getNoteTag([this, Notes{std::move(Notes)}](
387
11
                         PathSensitiveBugReport &BR) -> std::string {
388
11
          if (&BR.getBugType() != &UseAfterReleaseBugType &&
389
7
              &BR.getBugType() != &LeakBugType &&
390
2
              &BR.getBugType() != &DoubleReleaseBugType)
391
0
            return "";
392
12
          
for (auto &Note : Notes)11
{
393
12
            std::string Text = Note(BR);
394
12
            if (!Text.empty())
395
10
              return Text;
396
12
          }
397
1
          return "";
398
11
        });
399
63
  }
400
100
  C.addTransition(State, T);
401
100
}
402
403
void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
404
310
                                            CheckerContext &C) const {
405
310
  ProgramStateRef State = C.getState();
406
310
  SmallVector<SymbolRef, 2> LeakedSyms;
407
310
  HStateMapTy TrackedHandles = State->get<HStateMap>();
408
274
  for (auto &CurItem : TrackedHandles) {
409
274
    SymbolRef ErrorSym = CurItem.second.getErrorSym();
410
    // Keeping zombie handle symbols. In case the error symbol is dying later
411
    // than the handle symbol we might produce spurious leak warnings (in case
412
    // we find out later from the status code that the handle allocation failed
413
    // in the first place).
414
274
    if (!SymReaper.isDead(CurItem.first) ||
415
74
        (ErrorSym && 
!SymReaper.isDead(ErrorSym)7
))
416
204
      continue;
417
70
    if (CurItem.second.isAllocated() || 
CurItem.second.maybeAllocated()61
)
418
13
      LeakedSyms.push_back(CurItem.first);
419
70
    State = State->remove<HStateMap>(CurItem.first);
420
70
  }
421
422
310
  ExplodedNode *N = C.getPredecessor();
423
310
  if (!LeakedSyms.empty())
424
11
    N = reportLeaks(LeakedSyms, C, N);
425
426
310
  C.addTransition(State, N);
427
310
}
428
429
// Acquiring a handle is not always successful. In Fuchsia most functions
430
// return a status code that determines the status of the handle.
431
// When we split the path based on this status code we know that on one
432
// path we do have the handle and on the other path the acquire failed.
433
// This method helps avoiding false positive leak warnings on paths where
434
// the function failed.
435
// Moreover, when a handle is known to be zero (the invalid handle),
436
// we no longer can follow the symbol on the path, becaue the constant
437
// zero will be used instead of the symbol. We also do not need to release
438
// an invalid handle, so we remove the corresponding symbol from the state.
439
ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State,
440
                                                 SVal Cond,
441
275
                                                 bool Assumption) const {
442
  // TODO: add notes about successes/fails for APIs.
443
275
  ConstraintManager &Cmr = State->getConstraintManager();
444
275
  HStateMapTy TrackedHandles = State->get<HStateMap>();
445
358
  for (auto &CurItem : TrackedHandles) {
446
358
    ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first);
447
358
    if (HandleVal.isConstrainedTrue()) {
448
      // The handle is invalid. We can no longer follow the symbol on this path.
449
5
      State = State->remove<HStateMap>(CurItem.first);
450
5
    }
451
358
    SymbolRef ErrorSym = CurItem.second.getErrorSym();
452
358
    if (!ErrorSym)
453
166
      continue;
454
192
    ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym);
455
192
    if (ErrorVal.isConstrainedTrue()) {
456
      // Allocation succeeded.
457
24
      if (CurItem.second.maybeAllocated())
458
24
        State = State->set<HStateMap>(
459
24
            CurItem.first, HandleState::getAllocated(State, CurItem.second));
460
168
    } else if (ErrorVal.isConstrainedFalse()) {
461
      // Allocation failed.
462
26
      if (CurItem.second.maybeAllocated())
463
26
        State = State->remove<HStateMap>(CurItem.first);
464
26
    }
465
192
  }
466
275
  return State;
467
275
}
468
469
ProgramStateRef FuchsiaHandleChecker::checkPointerEscape(
470
    ProgramStateRef State, const InvalidatedSymbols &Escaped,
471
84
    const CallEvent *Call, PointerEscapeKind Kind) const {
472
84
  const FunctionDecl *FuncDecl =
473
79
      Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : 
nullptr5
;
474
475
84
  llvm::DenseSet<SymbolRef> UnEscaped;
476
  // Not all calls should escape our symbols.
477
84
  if (FuncDecl &&
478
78
      (Kind == PSK_DirectEscapeOnCall || 
Kind == PSK_IndirectEscapeOnCall71
||
479
78
       
Kind == PSK_EscapeOutParameters6
)) {
480
186
    for (unsigned Arg = 0; Arg < Call->getNumArgs(); 
++Arg108
) {
481
109
      if (Arg >= FuncDecl->getNumParams())
482
1
        break;
483
108
      const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg);
484
108
      SymbolRef Handle =
485
108
          getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State);
486
108
      if (!Handle)
487
22
        continue;
488
86
      if (hasFuchsiaAttr<UseHandleAttr>(PVD) ||
489
76
          hasFuchsiaAttr<ReleaseHandleAttr>(PVD))
490
48
        UnEscaped.insert(Handle);
491
86
    }
492
78
  }
493
494
  // For out params, we have to deal with derived symbols. See
495
  // MacOSKeychainAPIChecker for details.
496
102
  for (auto I : State->get<HStateMap>()) {
497
102
    if (Escaped.count(I.first) && 
!UnEscaped.count(I.first)13
)
498
12
      State = State->set<HStateMap>(I.first, HandleState::getEscaped());
499
102
    if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) {
500
19
      auto ParentSym = SD->getParentSymbol();
501
19
      if (Escaped.count(ParentSym))
502
1
        State = State->set<HStateMap>(I.first, HandleState::getEscaped());
503
19
    }
504
102
  }
505
506
84
  return State;
507
84
}
508
509
ExplodedNode *
510
FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
511
11
                                  CheckerContext &C, ExplodedNode *Pred) const {
512
11
  ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred);
513
13
  for (SymbolRef LeakedHandle : LeakedHandles) {
514
13
    reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType,
515
13
              "Potential leak of handle");
516
13
  }
517
11
  return ErrNode;
518
11
}
519
520
void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
521
                                               const SourceRange &Range,
522
1
                                               CheckerContext &C) const {
523
1
  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
524
1
  reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType,
525
1
            "Releasing a previously released handle");
526
1
}
527
528
void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
529
                                              const SourceRange &Range,
530
2
                                              CheckerContext &C) const {
531
2
  ExplodedNode *ErrNode = C.generateErrorNode(C.getState());
532
2
  reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType,
533
2
            "Using a previously released handle");
534
2
}
535
536
void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
537
                                     CheckerContext &C,
538
                                     const SourceRange *Range,
539
16
                                     const BugType &Type, StringRef Msg) const {
540
16
  if (!ErrorNode)
541
0
    return;
542
543
16
  std::unique_ptr<PathSensitiveBugReport> R;
544
16
  if (Type.isSuppressOnSink()) {
545
13
    const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
546
13
    if (AcquireNode) {
547
13
      PathDiagnosticLocation LocUsedForUniqueing =
548
13
          PathDiagnosticLocation::createBegin(
549
13
              AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
550
13
              AcquireNode->getLocationContext());
551
552
13
      R = std::make_unique<PathSensitiveBugReport>(
553
13
          Type, Msg, ErrorNode, LocUsedForUniqueing,
554
13
          AcquireNode->getLocationContext()->getDecl());
555
13
    }
556
13
  }
557
16
  if (!R)
558
3
    R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode);
559
16
  if (Range)
560
3
    R->addRange(*Range);
561
16
  R->markInteresting(Sym);
562
16
  C.emitReport(std::move(R));
563
16
}
564
565
1
void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) {
566
1
  mgr.registerChecker<FuchsiaHandleChecker>();
567
1
}
568
569
2
bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) {
570
2
  return true;
571
2
}
572
573
void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State,
574
0
                                      const char *NL, const char *Sep) const {
575
576
0
  HStateMapTy StateMap = State->get<HStateMap>();
577
578
0
  if (!StateMap.isEmpty()) {
579
0
    Out << Sep << "FuchsiaHandleChecker :" << NL;
580
0
    for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E;
581
0
         ++I) {
582
0
      I.getKey()->dumpToStream(Out);
583
0
      Out << " : ";
584
0
      I.getData().dump(Out);
585
0
      Out << NL;
586
0
    }
587
0
  }
588
0
}