clang  14.0.0git
MacOSKeychainAPIChecker.cpp
Go to the documentation of this file.
1 //==--- MacOSKeychainAPIChecker.cpp ------------------------------*- 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 // This checker flags misuses of KeyChainAPI. In particular, the password data
9 // allocated/returned by SecKeychainItemCopyContent,
10 // SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has
11 // to be freed using a call to SecKeychainItemFreeContent.
12 //===----------------------------------------------------------------------===//
13 
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
30  check::PostStmt<CallExpr>,
31  check::DeadSymbols,
32  check::PointerEscape,
33  eval::Assume> {
34  mutable std::unique_ptr<BugType> BT;
35 
36 public:
37  /// AllocationState is a part of the checker specific state together with the
38  /// MemRegion corresponding to the allocated data.
39  struct AllocationState {
40  /// The index of the allocator function.
41  unsigned int AllocatorIdx;
42  SymbolRef Region;
43 
44  AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) :
45  AllocatorIdx(Idx),
46  Region(R) {}
47 
48  bool operator==(const AllocationState &X) const {
49  return (AllocatorIdx == X.AllocatorIdx &&
50  Region == X.Region);
51  }
52 
53  void Profile(llvm::FoldingSetNodeID &ID) const {
54  ID.AddInteger(AllocatorIdx);
55  ID.AddPointer(Region);
56  }
57  };
58 
59  void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
60  void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
61  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
62  ProgramStateRef checkPointerEscape(ProgramStateRef State,
63  const InvalidatedSymbols &Escaped,
64  const CallEvent *Call,
65  PointerEscapeKind Kind) const;
66  ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
67  bool Assumption) const;
68  void printState(raw_ostream &Out, ProgramStateRef State,
69  const char *NL, const char *Sep) const override;
70 
71 private:
72  typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
73  typedef SmallVector<AllocationPair, 2> AllocationPairVec;
74 
75  enum APIKind {
76  /// Denotes functions tracked by this checker.
77  ValidAPI = 0,
78  /// The functions commonly/mistakenly used in place of the given API.
79  ErrorAPI = 1,
80  /// The functions which may allocate the data. These are tracked to reduce
81  /// the false alarm rate.
82  PossibleAPI = 2
83  };
84  /// Stores the information about the allocator and deallocator functions -
85  /// these are the functions the checker is tracking.
86  struct ADFunctionInfo {
87  const char* Name;
88  unsigned int Param;
89  unsigned int DeallocatorIdx;
90  APIKind Kind;
91  };
92  static const unsigned InvalidIdx = 100000;
93  static const unsigned FunctionsToTrackSize = 8;
94  static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize];
95  /// The value, which represents no error return value for allocator functions.
96  static const unsigned NoErr = 0;
97 
98  /// Given the function name, returns the index of the allocator/deallocator
99  /// function.
100  static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator);
101 
102  inline void initBugType() const {
103  if (!BT)
104  BT.reset(new BugType(this, "Improper use of SecKeychain API",
105  "API Misuse (Apple)"));
106  }
107 
108  void generateDeallocatorMismatchReport(const AllocationPair &AP,
109  const Expr *ArgExpr,
110  CheckerContext &C) const;
111 
112  /// Find the allocation site for Sym on the path leading to the node N.
113  const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
114  CheckerContext &C) const;
115 
116  std::unique_ptr<PathSensitiveBugReport>
117  generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
118  ExplodedNode *N,
119  CheckerContext &C) const;
120 
121  /// Mark an AllocationPair interesting for diagnostic reporting.
122  void markInteresting(PathSensitiveBugReport *R,
123  const AllocationPair &AP) const {
124  R->markInteresting(AP.first);
125  R->markInteresting(AP.second->Region);
126  }
127 
128  /// The bug visitor which allows us to print extra diagnostics along the
129  /// BugReport path. For example, showing the allocation site of the leaked
130  /// region.
131  class SecKeychainBugVisitor : public BugReporterVisitor {
132  protected:
133  // The allocated region symbol tracked by the main analysis.
134  SymbolRef Sym;
135 
136  public:
137  SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
138 
139  void Profile(llvm::FoldingSetNodeID &ID) const override {
140  static int X = 0;
141  ID.AddPointer(&X);
142  ID.AddPointer(Sym);
143  }
144 
145  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
146  BugReporterContext &BRC,
147  PathSensitiveBugReport &BR) override;
148  };
149 };
150 }
151 
152 /// ProgramState traits to store the currently allocated (and not yet freed)
153 /// symbols. This is a map from the allocated content symbol to the
154 /// corresponding AllocationState.
156  SymbolRef,
157  MacOSKeychainAPIChecker::AllocationState)
158 
159 static bool isEnclosingFunctionParam(const Expr *E) {
160  E = E->IgnoreParenCasts();
161  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
162  const ValueDecl *VD = DRE->getDecl();
163  if (isa<ImplicitParamDecl, ParmVarDecl>(VD))
164  return true;
165  }
166  return false;
167 }
168 
169 const MacOSKeychainAPIChecker::ADFunctionInfo
170  MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = {
171  {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0
172  {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1
173  {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2
174  {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3
175  {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4
176  {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5
177  {"free", 0, InvalidIdx, ErrorAPI}, // 6
178  {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7
179 };
180 
181 unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
182  bool IsAllocator) {
183  for (unsigned I = 0; I < FunctionsToTrackSize; ++I) {
184  ADFunctionInfo FI = FunctionsToTrack[I];
185  if (FI.Name != Name)
186  continue;
187  // Make sure the function is of the right type (allocator vs deallocator).
188  if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx))
189  return InvalidIdx;
190  if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx))
191  return InvalidIdx;
192 
193  return I;
194  }
195  // The function is not tracked.
196  return InvalidIdx;
197 }
198 
199 static bool isBadDeallocationArgument(const MemRegion *Arg) {
200  if (!Arg)
201  return false;
202  return isa<AllocaRegion, BlockDataRegion, TypedRegion>(Arg);
203 }
204 
205 /// Given the address expression, retrieve the value it's pointing to. Assume
206 /// that value is itself an address, and return the corresponding symbol.
208  CheckerContext &C) {
209  ProgramStateRef State = C.getState();
210  SVal ArgV = C.getSVal(Expr);
211 
212  if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
213  StoreManager& SM = C.getStoreManager();
214  SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
215  if (sym)
216  return sym;
217  }
218  return nullptr;
219 }
220 
221 // Report deallocator mismatch. Remove the region from tracking - reporting a
222 // missing free error after this one is redundant.
223 void MacOSKeychainAPIChecker::
224  generateDeallocatorMismatchReport(const AllocationPair &AP,
225  const Expr *ArgExpr,
226  CheckerContext &C) const {
227  ProgramStateRef State = C.getState();
228  State = State->remove<AllocatedData>(AP.first);
229  ExplodedNode *N = C.generateNonFatalErrorNode(State);
230 
231  if (!N)
232  return;
233  initBugType();
234  SmallString<80> sbuf;
235  llvm::raw_svector_ostream os(sbuf);
236  unsigned int PDeallocIdx =
237  FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx;
238 
239  os << "Deallocator doesn't match the allocator: '"
240  << FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
241  auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
242  Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
243  Report->addRange(ArgExpr->getSourceRange());
244  markInteresting(Report.get(), AP);
245  C.emitReport(std::move(Report));
246 }
247 
248 void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
249  CheckerContext &C) const {
250  unsigned idx = InvalidIdx;
251  ProgramStateRef State = C.getState();
252 
253  const FunctionDecl *FD = C.getCalleeDecl(CE);
254  if (!FD || FD->getKind() != Decl::Function)
255  return;
256 
257  StringRef funName = C.getCalleeName(FD);
258  if (funName.empty())
259  return;
260 
261  // If it is a call to an allocator function, it could be a double allocation.
262  idx = getTrackedFunctionIndex(funName, true);
263  if (idx != InvalidIdx) {
264  unsigned paramIdx = FunctionsToTrack[idx].Param;
265  if (CE->getNumArgs() <= paramIdx)
266  return;
267 
268  const Expr *ArgExpr = CE->getArg(paramIdx);
269  if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
270  if (const AllocationState *AS = State->get<AllocatedData>(V)) {
271  // Remove the value from the state. The new symbol will be added for
272  // tracking when the second allocator is processed in checkPostStmt().
273  State = State->remove<AllocatedData>(V);
274  ExplodedNode *N = C.generateNonFatalErrorNode(State);
275  if (!N)
276  return;
277  initBugType();
278  SmallString<128> sbuf;
279  llvm::raw_svector_ostream os(sbuf);
280  unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
281  os << "Allocated data should be released before another call to "
282  << "the allocator: missing a call to '"
283  << FunctionsToTrack[DIdx].Name
284  << "'.";
285  auto Report =
286  std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
287  Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(V));
288  Report->addRange(ArgExpr->getSourceRange());
289  Report->markInteresting(AS->Region);
290  C.emitReport(std::move(Report));
291  }
292  return;
293  }
294 
295  // Is it a call to one of deallocator functions?
296  idx = getTrackedFunctionIndex(funName, false);
297  if (idx == InvalidIdx)
298  return;
299 
300  unsigned paramIdx = FunctionsToTrack[idx].Param;
301  if (CE->getNumArgs() <= paramIdx)
302  return;
303 
304  // Check the argument to the deallocator.
305  const Expr *ArgExpr = CE->getArg(paramIdx);
306  SVal ArgSVal = C.getSVal(ArgExpr);
307 
308  // Undef is reported by another checker.
309  if (ArgSVal.isUndef())
310  return;
311 
312  SymbolRef ArgSM = ArgSVal.getAsLocSymbol();
313 
314  // If the argument is coming from the heap, globals, or unknown, do not
315  // report it.
316  bool RegionArgIsBad = false;
317  if (!ArgSM) {
318  if (!isBadDeallocationArgument(ArgSVal.getAsRegion()))
319  return;
320  RegionArgIsBad = true;
321  }
322 
323  // Is the argument to the call being tracked?
324  const AllocationState *AS = State->get<AllocatedData>(ArgSM);
325  if (!AS)
326  return;
327 
328  // TODO: We might want to report double free here.
329  // (that would involve tracking all the freed symbols in the checker state).
330  if (RegionArgIsBad) {
331  // It is possible that this is a false positive - the argument might
332  // have entered as an enclosing function parameter.
333  if (isEnclosingFunctionParam(ArgExpr))
334  return;
335 
336  ExplodedNode *N = C.generateNonFatalErrorNode(State);
337  if (!N)
338  return;
339  initBugType();
340  auto Report = std::make_unique<PathSensitiveBugReport>(
341  *BT, "Trying to free data which has not been allocated.", N);
342  Report->addRange(ArgExpr->getSourceRange());
343  if (AS)
344  Report->markInteresting(AS->Region);
345  C.emitReport(std::move(Report));
346  return;
347  }
348 
349  // Process functions which might deallocate.
350  if (FunctionsToTrack[idx].Kind == PossibleAPI) {
351 
352  if (funName == "CFStringCreateWithBytesNoCopy") {
353  const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
354  // NULL ~ default deallocator, so warn.
355  if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
357  const AllocationPair AP = std::make_pair(ArgSM, AS);
358  generateDeallocatorMismatchReport(AP, ArgExpr, C);
359  return;
360  }
361  // One of the default allocators, so warn.
362  if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
363  StringRef DeallocatorName = DE->getFoundDecl()->getName();
364  if (DeallocatorName == "kCFAllocatorDefault" ||
365  DeallocatorName == "kCFAllocatorSystemDefault" ||
366  DeallocatorName == "kCFAllocatorMalloc") {
367  const AllocationPair AP = std::make_pair(ArgSM, AS);
368  generateDeallocatorMismatchReport(AP, ArgExpr, C);
369  return;
370  }
371  // If kCFAllocatorNull, which does not deallocate, we still have to
372  // find the deallocator.
373  if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
374  return;
375  }
376  // In all other cases, assume the user supplied a correct deallocator
377  // that will free memory so stop tracking.
378  State = State->remove<AllocatedData>(ArgSM);
379  C.addTransition(State);
380  return;
381  }
382 
383  llvm_unreachable("We know of no other possible APIs.");
384  }
385 
386  // The call is deallocating a value we previously allocated, so remove it
387  // from the next state.
388  State = State->remove<AllocatedData>(ArgSM);
389 
390  // Check if the proper deallocator is used.
391  unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
392  if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
393  const AllocationPair AP = std::make_pair(ArgSM, AS);
394  generateDeallocatorMismatchReport(AP, ArgExpr, C);
395  return;
396  }
397 
398  C.addTransition(State);
399 }
400 
401 void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
402  CheckerContext &C) const {
403  ProgramStateRef State = C.getState();
404  const FunctionDecl *FD = C.getCalleeDecl(CE);
405  if (!FD || FD->getKind() != Decl::Function)
406  return;
407 
408  StringRef funName = C.getCalleeName(FD);
409 
410  // If a value has been allocated, add it to the set for tracking.
411  unsigned idx = getTrackedFunctionIndex(funName, true);
412  if (idx == InvalidIdx)
413  return;
414 
415  const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
416  // If the argument entered as an enclosing function parameter, skip it to
417  // avoid false positives.
418  if (isEnclosingFunctionParam(ArgExpr) &&
419  C.getLocationContext()->getParent() == nullptr)
420  return;
421 
422  if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
423  // If the argument points to something that's not a symbolic region, it
424  // can be:
425  // - unknown (cannot reason about it)
426  // - undefined (already reported by other checker)
427  // - constant (null - should not be tracked,
428  // other constant will generate a compiler warning)
429  // - goto (should be reported by other checker)
430 
431  // The call return value symbol should stay alive for as long as the
432  // allocated value symbol, since our diagnostics depend on the value
433  // returned by the call. Ex: Data should only be freed if noErr was
434  // returned during allocation.)
435  SymbolRef RetStatusSymbol = C.getSVal(CE).getAsSymbol();
436  C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
437 
438  // Track the allocated value in the checker state.
439  State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx,
440  RetStatusSymbol));
441  assert(State);
442  C.addTransition(State);
443  }
444 }
445 
446 // TODO: This logic is the same as in Malloc checker.
447 const ExplodedNode *
448 MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
449  SymbolRef Sym,
450  CheckerContext &C) const {
451  const LocationContext *LeakContext = N->getLocationContext();
452  // Walk the ExplodedGraph backwards and find the first node that referred to
453  // the tracked symbol.
454  const ExplodedNode *AllocNode = N;
455 
456  while (N) {
457  if (!N->getState()->get<AllocatedData>(Sym))
458  break;
459  // Allocation node, is the last node in the current or parent context in
460  // which the symbol was tracked.
461  const LocationContext *NContext = N->getLocationContext();
462  if (NContext == LeakContext ||
463  NContext->isParentOf(LeakContext))
464  AllocNode = N;
465  N = N->pred_empty() ? nullptr : *(N->pred_begin());
466  }
467 
468  return AllocNode;
469 }
470 
471 std::unique_ptr<PathSensitiveBugReport>
472 MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
473  const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const {
474  const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
475  initBugType();
476  SmallString<70> sbuf;
477  llvm::raw_svector_ostream os(sbuf);
478  os << "Allocated data is not released: missing a call to '"
479  << FunctionsToTrack[FI.DeallocatorIdx].Name << "'.";
480 
481  // Most bug reports are cached at the location where they occurred.
482  // With leaks, we want to unique them by the location where they were
483  // allocated, and only report a single path.
484  PathDiagnosticLocation LocUsedForUniqueing;
485  const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
486  const Stmt *AllocStmt = AllocNode->getStmtForDiagnostics();
487 
488  if (AllocStmt)
489  LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
490  C.getSourceManager(),
491  AllocNode->getLocationContext());
492 
493  auto Report = std::make_unique<PathSensitiveBugReport>(
494  *BT, os.str(), N, LocUsedForUniqueing,
495  AllocNode->getLocationContext()->getDecl());
496 
497  Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
498  markInteresting(Report.get(), AP);
499  return Report;
500 }
501 
502 /// If the return symbol is assumed to be error, remove the allocated info
503 /// from consideration.
504 ProgramStateRef MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State,
505  SVal Cond,
506  bool Assumption) const {
507  AllocatedDataTy AMap = State->get<AllocatedData>();
508  if (AMap.isEmpty())
509  return State;
510 
511  auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymbol());
512  if (!CondBSE)
513  return State;
514  BinaryOperator::Opcode OpCode = CondBSE->getOpcode();
515  if (OpCode != BO_EQ && OpCode != BO_NE)
516  return State;
517 
518  // Match for a restricted set of patterns for cmparison of error codes.
519  // Note, the comparisons of type '0 == st' are transformed into SymIntExpr.
520  SymbolRef ReturnSymbol = nullptr;
521  if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) {
522  const llvm::APInt &RHS = SIE->getRHS();
523  bool ErrorIsReturned = (OpCode == BO_EQ && RHS != NoErr) ||
524  (OpCode == BO_NE && RHS == NoErr);
525  if (!Assumption)
526  ErrorIsReturned = !ErrorIsReturned;
527  if (ErrorIsReturned)
528  ReturnSymbol = SIE->getLHS();
529  }
530 
531  if (ReturnSymbol)
532  for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
533  if (ReturnSymbol == I->second.Region)
534  State = State->remove<AllocatedData>(I->first);
535  }
536 
537  return State;
538 }
539 
540 void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
541  CheckerContext &C) const {
542  ProgramStateRef State = C.getState();
543  AllocatedDataTy AMap = State->get<AllocatedData>();
544  if (AMap.isEmpty())
545  return;
546 
547  bool Changed = false;
548  AllocationPairVec Errors;
549  for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
550  if (!SR.isDead(I->first))
551  continue;
552 
553  Changed = true;
554  State = State->remove<AllocatedData>(I->first);
555  // If the allocated symbol is null do not report.
556  ConstraintManager &CMgr = State->getConstraintManager();
557  ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey());
558  if (AllocFailed.isConstrainedTrue())
559  continue;
560  Errors.push_back(std::make_pair(I->first, &I->second));
561  }
562  if (!Changed) {
563  // Generate the new, cleaned up state.
564  C.addTransition(State);
565  return;
566  }
567 
568  static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak");
569  ExplodedNode *N = C.generateNonFatalErrorNode(C.getState(), &Tag);
570  if (!N)
571  return;
572 
573  // Generate the error reports.
574  for (const auto &P : Errors)
575  C.emitReport(generateAllocatedDataNotReleasedReport(P, N, C));
576 
577  // Generate the new, cleaned up state.
578  C.addTransition(State, N);
579 }
580 
581 ProgramStateRef MacOSKeychainAPIChecker::checkPointerEscape(
582  ProgramStateRef State, const InvalidatedSymbols &Escaped,
583  const CallEvent *Call, PointerEscapeKind Kind) const {
584  // FIXME: This branch doesn't make any sense at all, but it is an overfitted
585  // replacement for a previous overfitted code that was making even less sense.
586  if (!Call || Call->getDecl())
587  return State;
588 
589  for (auto I : State->get<AllocatedData>()) {
590  SymbolRef Sym = I.first;
591  if (Escaped.count(Sym))
592  State = State->remove<AllocatedData>(Sym);
593 
594  // This checker is special. Most checkers in fact only track symbols of
595  // SymbolConjured type, eg. symbols returned from functions such as
596  // malloc(). This checker tracks symbols returned as out-parameters.
597  //
598  // When a function is evaluated conservatively, the out-parameter's pointee
599  // base region gets invalidated with a SymbolConjured. If the base region is
600  // larger than the region we're interested in, the value we're interested in
601  // would be SymbolDerived based on that SymbolConjured. However, such
602  // SymbolDerived will never be listed in the Escaped set when the base
603  // region is invalidated because ExprEngine doesn't know which symbols
604  // were derived from a given symbol, while there can be infinitely many
605  // valid symbols derived from any given symbol.
606  //
607  // Hence the extra boilerplate: remove the derived symbol when its parent
608  // symbol escapes.
609  //
610  if (const auto *SD = dyn_cast<SymbolDerived>(Sym)) {
611  SymbolRef ParentSym = SD->getParentSymbol();
612  if (Escaped.count(ParentSym))
613  State = State->remove<AllocatedData>(Sym);
614  }
615  }
616  return State;
617 }
618 
620 MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
621  const ExplodedNode *N, BugReporterContext &BRC,
622  PathSensitiveBugReport &BR) {
623  const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
624  if (!AS)
625  return nullptr;
626  const AllocationState *ASPrev =
627  N->getFirstPred()->getState()->get<AllocatedData>(Sym);
628  if (ASPrev)
629  return nullptr;
630 
631  // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
632  // allocation site.
633  const CallExpr *CE =
634  cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
635  const FunctionDecl *funDecl = CE->getDirectCallee();
636  assert(funDecl && "We do not support indirect function calls as of now.");
637  StringRef funName = funDecl->getName();
638 
639  // Get the expression of the corresponding argument.
640  unsigned Idx = getTrackedFunctionIndex(funName, true);
641  assert(Idx != InvalidIdx && "This should be a call to an allocator.");
642  const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param);
643  PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(),
644  N->getLocationContext());
645  return std::make_shared<PathDiagnosticEventPiece>(Pos,
646  "Data is allocated here.");
647 }
648 
649 void MacOSKeychainAPIChecker::printState(raw_ostream &Out,
651  const char *NL,
652  const char *Sep) const {
653 
654  AllocatedDataTy AMap = State->get<AllocatedData>();
655 
656  if (!AMap.isEmpty()) {
657  Out << Sep << "KeychainAPIChecker :" << NL;
658  for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
659  I.getKey()->dumpToStream(Out);
660  }
661  }
662 }
663 
664 
665 void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
666  mgr.registerChecker<MacOSKeychainAPIChecker>();
667 }
668 
669 bool ento::shouldRegisterMacOSKeychainAPIChecker(const CheckerManager &mgr) {
670  return true;
671 }
clang::interp::APInt
llvm::APInt APInt
Definition: Integral.h:27
clang::LocationContext
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Definition: AnalysisDeclContext.h:215
clang::ento::PathDiagnosticPieceRef
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
Definition: PathDiagnostic.h:494
llvm::SmallVector
Definition: LLVM.h:38
clang::Stmt::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:324
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
llvm::Optional
Definition: LLVM.h:40
clang::tooling::X
static ToolExecutorPluginRegistry::Add< AllTUsToolExecutorPlugin > X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. " "Tool results are stored in memory.")
clang::index::SymbolRole::Call
@ Call
getAsPointeeSymbol
static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C)
Given the address expression, retrieve the value it's pointing to.
Definition: MacOSKeychainAPIChecker.cpp:207
CallEvent.h
V
#define V(N, I)
Definition: ASTContext.h:3121
isBadDeallocationArgument
static bool isBadDeallocationArgument(const MemRegion *Arg)
Definition: MacOSKeychainAPIChecker.cpp:199
clang::CallExpr::getDirectCallee
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:2965
BuiltinCheckerRegistration.h
clang::StmtPoint
Definition: ProgramPoint.h:271
clang::Decl::getKind
Kind getKind() const
Definition: DeclBase.h:433
CheckerManager.h
clang::LocationContext::isParentOf
bool isParentOf(const LocationContext *LC) const
Definition: AnalysisDeclContext.cpp:477
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2986
clang::Expr::NPC_ValueDependentIsNotNull
@ NPC_ValueDependentIsNotNull
Specifies that a value-dependent expression should be considered to never be a null pointer constant.
Definition: Expr.h:784
llvm::SmallString
Definition: LLVM.h:37
clang::StmtPoint::getStmt
const Stmt * getStmt() const
Definition: ProgramPoint.h:279
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
clang::Expr::IgnoreParenCasts
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:2924
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
BugType.h
clang::ValueDecl
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:676
clang::CallExpr::getNumArgs
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2973
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
clang::BinaryOperatorKind
BinaryOperatorKind
Definition: OperationKinds.h:25
clang::Expr::isNullPointerConstant
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to a Null pointer constant.
Definition: Expr.cpp:3741
CheckerContext.h
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
ProgramState.h
REGISTER_MAP_WITH_PROGRAMSTATE
REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, SymbolRef, MacOSKeychainAPIChecker::AllocationState) static bool isEnclosingFunctionParam(const Expr *E)
ProgramState traits to store the currently allocated (and not yet freed) symbols.
Definition: MacOSKeychainAPIChecker.cpp:155
Checker.h
clang::Builtin::ID
ID
Definition: Builtins.h:48
clang
Definition: CalledOnceCheck.h:17
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:69
clang::ento::PathDiagnosticLocation::createBegin
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Definition: PathDiagnostic.cpp:580
clang::ento::PointerEscapeKind
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Definition: CheckerManager.h:79
ProgramStateTrait.h
clang::Expr
This represents one expression.
Definition: Expr.h:109
SM
#define SM(sm)
Definition: Cuda.cpp:78
clang::ento::InvalidatedSymbols
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
clang::DeclRefExpr
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1217
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2795
clang::operator==
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition: CallGraph.h:207
clang::NamedDecl::getName
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276