MacOSKeychainAPIChecker.cpp 23 KB

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