MacOSKeychainAPIChecker.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. //==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // This checker flags misuses of KeyChainAPI. In particular, the password data
  10. // allocated/returned by SecKeychainItemCopyContent,
  11. // SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has
  12. // to be freed using a call to SecKeychainItemFreeContent.
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  16. #include "clang/StaticAnalyzer/Core/Checker.h"
  17. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
  21. #include "llvm/ADT/SmallString.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. using namespace clang;
  24. using namespace ento;
  25. namespace {
  26. class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
  27. check::PostStmt<CallExpr>,
  28. check::DeadSymbols> {
  29. mutable std::unique_ptr<BugType> BT;
  30. public:
  31. /// AllocationState is a part of the checker specific state together with the
  32. /// MemRegion corresponding to the allocated data.
  33. struct AllocationState {
  34. /// The index of the allocator function.
  35. unsigned int AllocatorIdx;
  36. SymbolRef Region;
  37. AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) :
  38. AllocatorIdx(Idx),
  39. Region(R) {}
  40. bool operator==(const AllocationState &X) const {
  41. return (AllocatorIdx == X.AllocatorIdx &&
  42. Region == X.Region);
  43. }
  44. void Profile(llvm::FoldingSetNodeID &ID) const {
  45. ID.AddInteger(AllocatorIdx);
  46. ID.AddPointer(Region);
  47. }
  48. };
  49. void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
  50. void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
  51. void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
  52. private:
  53. typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
  54. typedef SmallVector<AllocationPair, 2> AllocationPairVec;
  55. enum APIKind {
  56. /// Denotes functions tracked by this checker.
  57. ValidAPI = 0,
  58. /// The functions commonly/mistakenly used in place of the given API.
  59. ErrorAPI = 1,
  60. /// The functions which may allocate the data. These are tracked to reduce
  61. /// the false alarm rate.
  62. PossibleAPI = 2
  63. };
  64. /// Stores the information about the allocator and deallocator functions -
  65. /// these are the functions the checker is tracking.
  66. struct ADFunctionInfo {
  67. const char* Name;
  68. unsigned int Param;
  69. unsigned int DeallocatorIdx;
  70. APIKind Kind;
  71. };
  72. static const unsigned InvalidIdx = 100000;
  73. static const unsigned FunctionsToTrackSize = 8;
  74. static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize];
  75. /// The value, which represents no error return value for allocator functions.
  76. static const unsigned NoErr = 0;
  77. /// Given the function name, returns the index of the allocator/deallocator
  78. /// function.
  79. static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator);
  80. inline void initBugType() const {
  81. if (!BT)
  82. BT.reset(new BugType(this, "Improper use of SecKeychain API",
  83. "API Misuse (Apple)"));
  84. }
  85. void generateDeallocatorMismatchReport(const AllocationPair &AP,
  86. const Expr *ArgExpr,
  87. CheckerContext &C) const;
  88. /// Find the allocation site for Sym on the path leading to the node N.
  89. const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
  90. CheckerContext &C) const;
  91. std::unique_ptr<BugReport> generateAllocatedDataNotReleasedReport(
  92. const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const;
  93. /// Check if RetSym evaluates to an error value in the current state.
  94. bool definitelyReturnedError(SymbolRef RetSym,
  95. ProgramStateRef State,
  96. SValBuilder &Builder,
  97. bool noError = false) const;
  98. /// Check if RetSym evaluates to a NoErr value in the current state.
  99. bool definitelyDidnotReturnError(SymbolRef RetSym,
  100. ProgramStateRef State,
  101. SValBuilder &Builder) const {
  102. return definitelyReturnedError(RetSym, State, Builder, true);
  103. }
  104. /// Mark an AllocationPair interesting for diagnostic reporting.
  105. void markInteresting(BugReport *R, const AllocationPair &AP) const {
  106. R->markInteresting(AP.first);
  107. R->markInteresting(AP.second->Region);
  108. }
  109. /// The bug visitor which allows us to print extra diagnostics along the
  110. /// BugReport path. For example, showing the allocation site of the leaked
  111. /// region.
  112. class SecKeychainBugVisitor
  113. : public BugReporterVisitorImpl<SecKeychainBugVisitor> {
  114. protected:
  115. // The allocated region symbol tracked by the main analysis.
  116. SymbolRef Sym;
  117. public:
  118. SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
  119. ~SecKeychainBugVisitor() override {}
  120. void Profile(llvm::FoldingSetNodeID &ID) const override {
  121. static int X = 0;
  122. ID.AddPointer(&X);
  123. ID.AddPointer(Sym);
  124. }
  125. PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
  126. const ExplodedNode *PrevN,
  127. BugReporterContext &BRC,
  128. BugReport &BR) override;
  129. };
  130. };
  131. }
  132. /// ProgramState traits to store the currently allocated (and not yet freed)
  133. /// symbols. This is a map from the allocated content symbol to the
  134. /// corresponding AllocationState.
  135. REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData,
  136. SymbolRef,
  137. MacOSKeychainAPIChecker::AllocationState)
  138. static bool isEnclosingFunctionParam(const Expr *E) {
  139. E = E->IgnoreParenCasts();
  140. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
  141. const ValueDecl *VD = DRE->getDecl();
  142. if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD))
  143. return true;
  144. }
  145. return false;
  146. }
  147. const MacOSKeychainAPIChecker::ADFunctionInfo
  148. MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = {
  149. {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0
  150. {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1
  151. {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2
  152. {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3
  153. {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4
  154. {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5
  155. {"free", 0, InvalidIdx, ErrorAPI}, // 6
  156. {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7
  157. };
  158. unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
  159. bool IsAllocator) {
  160. for (unsigned I = 0; I < FunctionsToTrackSize; ++I) {
  161. ADFunctionInfo FI = FunctionsToTrack[I];
  162. if (FI.Name != Name)
  163. continue;
  164. // Make sure the function is of the right type (allocator vs deallocator).
  165. if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx))
  166. return InvalidIdx;
  167. if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx))
  168. return InvalidIdx;
  169. return I;
  170. }
  171. // The function is not tracked.
  172. return InvalidIdx;
  173. }
  174. static bool isBadDeallocationArgument(const MemRegion *Arg) {
  175. if (!Arg)
  176. return false;
  177. if (isa<AllocaRegion>(Arg) ||
  178. isa<BlockDataRegion>(Arg) ||
  179. isa<TypedRegion>(Arg)) {
  180. return true;
  181. }
  182. return false;
  183. }
  184. /// Given the address expression, retrieve the value it's pointing to. Assume
  185. /// that value is itself an address, and return the corresponding symbol.
  186. static SymbolRef getAsPointeeSymbol(const Expr *Expr,
  187. CheckerContext &C) {
  188. ProgramStateRef State = C.getState();
  189. SVal ArgV = State->getSVal(Expr, C.getLocationContext());
  190. if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
  191. StoreManager& SM = C.getStoreManager();
  192. SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
  193. if (sym)
  194. return sym;
  195. }
  196. return nullptr;
  197. }
  198. // When checking for error code, we need to consider the following cases:
  199. // 1) noErr / [0]
  200. // 2) someErr / [1, inf]
  201. // 3) unknown
  202. // If noError, returns true iff (1).
  203. // If !noError, returns true iff (2).
  204. bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym,
  205. ProgramStateRef State,
  206. SValBuilder &Builder,
  207. bool noError) const {
  208. DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr,
  209. Builder.getSymbolManager().getType(RetSym));
  210. DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal,
  211. nonloc::SymbolVal(RetSym));
  212. ProgramStateRef ErrState = State->assume(NoErr, noError);
  213. if (ErrState == State) {
  214. return true;
  215. }
  216. return false;
  217. }
  218. // Report deallocator mismatch. Remove the region from tracking - reporting a
  219. // missing free error after this one is redundant.
  220. void MacOSKeychainAPIChecker::
  221. generateDeallocatorMismatchReport(const AllocationPair &AP,
  222. const Expr *ArgExpr,
  223. CheckerContext &C) const {
  224. ProgramStateRef State = C.getState();
  225. State = State->remove<AllocatedData>(AP.first);
  226. ExplodedNode *N = C.addTransition(State);
  227. if (!N)
  228. return;
  229. initBugType();
  230. SmallString<80> sbuf;
  231. llvm::raw_svector_ostream os(sbuf);
  232. unsigned int PDeallocIdx =
  233. FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx;
  234. os << "Deallocator doesn't match the allocator: '"
  235. << FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
  236. auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
  237. Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
  238. Report->addRange(ArgExpr->getSourceRange());
  239. markInteresting(Report.get(), AP);
  240. C.emitReport(std::move(Report));
  241. }
  242. void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
  243. CheckerContext &C) const {
  244. unsigned idx = InvalidIdx;
  245. ProgramStateRef State = C.getState();
  246. const FunctionDecl *FD = C.getCalleeDecl(CE);
  247. if (!FD || FD->getKind() != Decl::Function)
  248. return;
  249. StringRef funName = C.getCalleeName(FD);
  250. if (funName.empty())
  251. return;
  252. // If it is a call to an allocator function, it could be a double allocation.
  253. idx = getTrackedFunctionIndex(funName, true);
  254. if (idx != InvalidIdx) {
  255. unsigned paramIdx = FunctionsToTrack[idx].Param;
  256. if (CE->getNumArgs() <= paramIdx)
  257. return;
  258. const Expr *ArgExpr = CE->getArg(paramIdx);
  259. if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
  260. if (const AllocationState *AS = State->get<AllocatedData>(V)) {
  261. if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
  262. // Remove the value from the state. The new symbol will be added for
  263. // tracking when the second allocator is processed in checkPostStmt().
  264. State = State->remove<AllocatedData>(V);
  265. ExplodedNode *N = C.addTransition(State);
  266. if (!N)
  267. return;
  268. initBugType();
  269. SmallString<128> sbuf;
  270. llvm::raw_svector_ostream os(sbuf);
  271. unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
  272. os << "Allocated data should be released before another call to "
  273. << "the allocator: missing a call to '"
  274. << FunctionsToTrack[DIdx].Name
  275. << "'.";
  276. auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
  277. Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V));
  278. Report->addRange(ArgExpr->getSourceRange());
  279. Report->markInteresting(AS->Region);
  280. C.emitReport(std::move(Report));
  281. }
  282. }
  283. return;
  284. }
  285. // Is it a call to one of deallocator functions?
  286. idx = getTrackedFunctionIndex(funName, false);
  287. if (idx == InvalidIdx)
  288. return;
  289. unsigned paramIdx = FunctionsToTrack[idx].Param;
  290. if (CE->getNumArgs() <= paramIdx)
  291. return;
  292. // Check the argument to the deallocator.
  293. const Expr *ArgExpr = CE->getArg(paramIdx);
  294. SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext());
  295. // Undef is reported by another checker.
  296. if (ArgSVal.isUndef())
  297. return;
  298. SymbolRef ArgSM = ArgSVal.getAsLocSymbol();
  299. // If the argument is coming from the heap, globals, or unknown, do not
  300. // report it.
  301. bool RegionArgIsBad = false;
  302. if (!ArgSM) {
  303. if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
  304. return;
  305. RegionArgIsBad = true;
  306. }
  307. // Is the argument to the call being tracked?
  308. const AllocationState *AS = State->get<AllocatedData>(ArgSM);
  309. if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
  310. return;
  311. }
  312. // If trying to free data which has not been allocated yet, report as a bug.
  313. // TODO: We might want a more precise diagnostic for double free
  314. // (that would involve tracking all the freed symbols in the checker state).
  315. if (!AS || RegionArgIsBad) {
  316. // It is possible that this is a false positive - the argument might
  317. // have entered as an enclosing function parameter.
  318. if (isEnclosingFunctionParam(ArgExpr))
  319. return;
  320. ExplodedNode *N = C.addTransition(State);
  321. if (!N)
  322. return;
  323. initBugType();
  324. auto Report = llvm::make_unique<BugReport>(
  325. *BT, "Trying to free data which has not been allocated.", N);
  326. Report->addRange(ArgExpr->getSourceRange());
  327. if (AS)
  328. Report->markInteresting(AS->Region);
  329. C.emitReport(std::move(Report));
  330. return;
  331. }
  332. // Process functions which might deallocate.
  333. if (FunctionsToTrack[idx].Kind == PossibleAPI) {
  334. if (funName == "CFStringCreateWithBytesNoCopy") {
  335. const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
  336. // NULL ~ default deallocator, so warn.
  337. if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
  338. Expr::NPC_ValueDependentIsNotNull)) {
  339. const AllocationPair AP = std::make_pair(ArgSM, AS);
  340. generateDeallocatorMismatchReport(AP, ArgExpr, C);
  341. return;
  342. }
  343. // One of the default allocators, so warn.
  344. if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
  345. StringRef DeallocatorName = DE->getFoundDecl()->getName();
  346. if (DeallocatorName == "kCFAllocatorDefault" ||
  347. DeallocatorName == "kCFAllocatorSystemDefault" ||
  348. DeallocatorName == "kCFAllocatorMalloc") {
  349. const AllocationPair AP = std::make_pair(ArgSM, AS);
  350. generateDeallocatorMismatchReport(AP, ArgExpr, C);
  351. return;
  352. }
  353. // If kCFAllocatorNull, which does not deallocate, we still have to
  354. // find the deallocator.
  355. if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
  356. return;
  357. }
  358. // In all other cases, assume the user supplied a correct deallocator
  359. // that will free memory so stop tracking.
  360. State = State->remove<AllocatedData>(ArgSM);
  361. C.addTransition(State);
  362. return;
  363. }
  364. llvm_unreachable("We know of no other possible APIs.");
  365. }
  366. // The call is deallocating a value we previously allocated, so remove it
  367. // from the next state.
  368. State = State->remove<AllocatedData>(ArgSM);
  369. // Check if the proper deallocator is used.
  370. unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
  371. if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
  372. const AllocationPair AP = std::make_pair(ArgSM, AS);
  373. generateDeallocatorMismatchReport(AP, ArgExpr, C);
  374. return;
  375. }
  376. // If the buffer can be null and the return status can be an error,
  377. // report a bad call to free.
  378. if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
  379. !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
  380. ExplodedNode *N = C.addTransition(State);
  381. if (!N)
  382. return;
  383. initBugType();
  384. auto Report = llvm::make_unique<BugReport>(
  385. *BT, "Only call free if a valid (non-NULL) buffer was returned.", N);
  386. Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(ArgSM));
  387. Report->addRange(ArgExpr->getSourceRange());
  388. Report->markInteresting(AS->Region);
  389. C.emitReport(std::move(Report));
  390. return;
  391. }
  392. C.addTransition(State);
  393. }
  394. void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
  395. CheckerContext &C) const {
  396. ProgramStateRef State = C.getState();
  397. const FunctionDecl *FD = C.getCalleeDecl(CE);
  398. if (!FD || FD->getKind() != Decl::Function)
  399. return;
  400. StringRef funName = C.getCalleeName(FD);
  401. // If a value has been allocated, add it to the set for tracking.
  402. unsigned idx = getTrackedFunctionIndex(funName, true);
  403. if (idx == InvalidIdx)
  404. return;
  405. const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
  406. // If the argument entered as an enclosing function parameter, skip it to
  407. // avoid false positives.
  408. if (isEnclosingFunctionParam(ArgExpr) &&
  409. C.getLocationContext()->getParent() == nullptr)
  410. return;
  411. if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
  412. // If the argument points to something that's not a symbolic region, it
  413. // can be:
  414. // - unknown (cannot reason about it)
  415. // - undefined (already reported by other checker)
  416. // - constant (null - should not be tracked,
  417. // other constant will generate a compiler warning)
  418. // - goto (should be reported by other checker)
  419. // The call return value symbol should stay alive for as long as the
  420. // allocated value symbol, since our diagnostics depend on the value
  421. // returned by the call. Ex: Data should only be freed if noErr was
  422. // returned during allocation.)
  423. SymbolRef RetStatusSymbol =
  424. State->getSVal(CE, C.getLocationContext()).getAsSymbol();
  425. C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
  426. // Track the allocated value in the checker state.
  427. State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx,
  428. RetStatusSymbol));
  429. assert(State);
  430. C.addTransition(State);
  431. }
  432. }
  433. // TODO: This logic is the same as in Malloc checker.
  434. const ExplodedNode *
  435. MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
  436. SymbolRef Sym,
  437. CheckerContext &C) const {
  438. const LocationContext *LeakContext = N->getLocationContext();
  439. // Walk the ExplodedGraph backwards and find the first node that referred to
  440. // the tracked symbol.
  441. const ExplodedNode *AllocNode = N;
  442. while (N) {
  443. if (!N->getState()->get<AllocatedData>(Sym))
  444. break;
  445. // Allocation node, is the last node in the current or parent context in
  446. // which the symbol was tracked.
  447. const LocationContext *NContext = N->getLocationContext();
  448. if (NContext == LeakContext ||
  449. NContext->isParentOf(LeakContext))
  450. AllocNode = N;
  451. N = N->pred_empty() ? nullptr : *(N->pred_begin());
  452. }
  453. return AllocNode;
  454. }
  455. std::unique_ptr<BugReport>
  456. MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
  457. const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const {
  458. const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
  459. initBugType();
  460. SmallString<70> sbuf;
  461. llvm::raw_svector_ostream os(sbuf);
  462. os << "Allocated data is not released: missing a call to '"
  463. << FunctionsToTrack[FI.DeallocatorIdx].Name << "'.";
  464. // Most bug reports are cached at the location where they occurred.
  465. // With leaks, we want to unique them by the location where they were
  466. // allocated, and only report a single path.
  467. PathDiagnosticLocation LocUsedForUniqueing;
  468. const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
  469. const Stmt *AllocStmt = nullptr;
  470. ProgramPoint P = AllocNode->getLocation();
  471. if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
  472. AllocStmt = Exit->getCalleeContext()->getCallSite();
  473. else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>())
  474. AllocStmt = PS->getStmt();
  475. if (AllocStmt)
  476. LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
  477. C.getSourceManager(),
  478. AllocNode->getLocationContext());
  479. auto Report =
  480. llvm::make_unique<BugReport>(*BT, os.str(), N, LocUsedForUniqueing,
  481. AllocNode->getLocationContext()->getDecl());
  482. Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
  483. markInteresting(Report.get(), AP);
  484. return Report;
  485. }
  486. void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
  487. CheckerContext &C) const {
  488. ProgramStateRef State = C.getState();
  489. AllocatedDataTy ASet = State->get<AllocatedData>();
  490. if (ASet.isEmpty())
  491. return;
  492. bool Changed = false;
  493. AllocationPairVec Errors;
  494. for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
  495. if (SR.isLive(I->first))
  496. continue;
  497. Changed = true;
  498. State = State->remove<AllocatedData>(I->first);
  499. // If the allocated symbol is null or if the allocation call might have
  500. // returned an error, do not report.
  501. ConstraintManager &CMgr = State->getConstraintManager();
  502. ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey());
  503. if (AllocFailed.isConstrainedTrue() ||
  504. definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
  505. continue;
  506. Errors.push_back(std::make_pair(I->first, &I->second));
  507. }
  508. if (!Changed) {
  509. // Generate the new, cleaned up state.
  510. C.addTransition(State);
  511. return;
  512. }
  513. static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak");
  514. ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
  515. // Generate the error reports.
  516. for (const auto P : Errors)
  517. C.emitReport(generateAllocatedDataNotReleasedReport(P, N, C));
  518. // Generate the new, cleaned up state.
  519. C.addTransition(State, N);
  520. }
  521. PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
  522. const ExplodedNode *N,
  523. const ExplodedNode *PrevN,
  524. BugReporterContext &BRC,
  525. BugReport &BR) {
  526. const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
  527. if (!AS)
  528. return nullptr;
  529. const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym);
  530. if (ASPrev)
  531. return nullptr;
  532. // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
  533. // allocation site.
  534. const CallExpr *CE =
  535. cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
  536. const FunctionDecl *funDecl = CE->getDirectCallee();
  537. assert(funDecl && "We do not support indirect function calls as of now.");
  538. StringRef funName = funDecl->getName();
  539. // Get the expression of the corresponding argument.
  540. unsigned Idx = getTrackedFunctionIndex(funName, true);
  541. assert(Idx != InvalidIdx && "This should be a call to an allocator.");
  542. const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param);
  543. PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(),
  544. N->getLocationContext());
  545. return new PathDiagnosticEventPiece(Pos, "Data is allocated here.");
  546. }
  547. void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
  548. mgr.registerChecker<MacOSKeychainAPIChecker>();
  549. }