FuchsiaHandleChecker.cpp 28 KB

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