clang 23.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 <optional>
23
24using namespace clang;
25using namespace ento;
26
27namespace {
28class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
29 check::PostStmt<CallExpr>,
30 check::DeadSymbols,
31 check::PointerEscape,
32 eval::Assume> {
33 const BugType BT{this, "Improper use of SecKeychain API",
35
36public:
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
71private:
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 void generateDeallocatorMismatchReport(const AllocationPair &AP,
103 const Expr *ArgExpr,
104 CheckerContext &C) const;
105
106 /// Find the allocation site for Sym on the path leading to the node N.
107 const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
108 CheckerContext &C) const;
109
110 std::unique_ptr<PathSensitiveBugReport>
111 generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
112 ExplodedNode *N,
113 CheckerContext &C) const;
114
115 /// Mark an AllocationPair interesting for diagnostic reporting.
116 void markInteresting(PathSensitiveBugReport *R,
117 const AllocationPair &AP) const {
118 R->markInteresting(AP.first);
119 R->markInteresting(AP.second->Region);
120 }
121
122 /// The bug visitor which allows us to print extra diagnostics along the
123 /// BugReport path. For example, showing the allocation site of the leaked
124 /// region.
125 class SecKeychainBugVisitor : public BugReporterVisitor {
126 protected:
127 // The allocated region symbol tracked by the main analysis.
128 SymbolRef Sym;
129
130 public:
131 SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
132
133 void Profile(llvm::FoldingSetNodeID &ID) const override {
134 static int X = 0;
135 ID.AddPointer(&X);
136 ID.AddPointer(Sym);
137 }
138
139 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
140 BugReporterContext &BRC,
141 PathSensitiveBugReport &BR) override;
142 };
143};
144}
145
146/// ProgramState traits to store the currently allocated (and not yet freed)
147/// symbols. This is a map from the allocated content symbol to the
148/// corresponding AllocationState.
150 SymbolRef,
151 MacOSKeychainAPIChecker::AllocationState)
152
153static bool isEnclosingFunctionParam(const Expr *E) {
154 E = E->IgnoreParenCasts();
155 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
156 const ValueDecl *VD = DRE->getDecl();
158 return true;
159 }
160 return false;
161}
162
163const MacOSKeychainAPIChecker::ADFunctionInfo
164 MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = {
165 {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0
166 {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1
167 {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2
168 {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3
169 {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4
170 {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5
171 {"free", 0, InvalidIdx, ErrorAPI}, // 6
172 {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7
173};
174
175unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
176 bool IsAllocator) {
177 for (unsigned I = 0; I < FunctionsToTrackSize; ++I) {
178 ADFunctionInfo FI = FunctionsToTrack[I];
179 if (FI.Name != Name)
180 continue;
181 // Make sure the function is of the right type (allocator vs deallocator).
182 if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx))
183 return InvalidIdx;
184 if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx))
185 return InvalidIdx;
186
187 return I;
188 }
189 // The function is not tracked.
190 return InvalidIdx;
191}
192
193static bool isBadDeallocationArgument(const MemRegion *Arg) {
194 if (!Arg)
195 return false;
197}
198
199/// Given the address expression, retrieve the value it's pointing to. Assume
200/// that value is itself an address, and return the corresponding symbol.
202 CheckerContext &C) {
203 ProgramStateRef State = C.getState();
204 SVal ArgV = C.getSVal(Expr);
205
206 if (std::optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
207 StoreManager& SM = C.getStoreManager();
208 SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
209 if (sym)
210 return sym;
211 }
212 return nullptr;
213}
214
215// Report deallocator mismatch. Remove the region from tracking - reporting a
216// missing free error after this one is redundant.
217void MacOSKeychainAPIChecker::
218 generateDeallocatorMismatchReport(const AllocationPair &AP,
219 const Expr *ArgExpr,
220 CheckerContext &C) const {
221 ProgramStateRef State = C.getState();
222 State = State->remove<AllocatedData>(AP.first);
223 ExplodedNode *N = C.generateNonFatalErrorNode(State);
224
225 if (!N)
226 return;
227 unsigned int PDeallocIdx =
228 FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx;
229
230 auto Report = std::make_unique<PathSensitiveBugReport>(
231 BT,
232 "Deallocator doesn't match the allocator: '" +
233 Twine(FunctionsToTrack[PDeallocIdx].Name) + "' should be used.",
234 N);
235 Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
236 Report->addRange(ArgExpr->getSourceRange());
237 markInteresting(Report.get(), AP);
238 C.emitReport(std::move(Report));
239}
240
241void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
242 CheckerContext &C) const {
243 unsigned idx = InvalidIdx;
244 ProgramStateRef State = C.getState();
245
246 const FunctionDecl *FD = C.getCalleeDecl(CE);
247 if (!FD || FD->getKind() != Decl::Function)
248 return;
249
250 StringRef funName = C.getCalleeName(FD);
251 if (funName.empty())
252 return;
253
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 unsigned paramIdx = FunctionsToTrack[idx].Param;
258 if (CE->getNumArgs() <= paramIdx)
259 return;
260
261 const Expr *ArgExpr = CE->getArg(paramIdx);
262 if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
263 if (const AllocationState *AS = State->get<AllocatedData>(V)) {
264 // Remove the value from the state. The new symbol will be added for
265 // tracking when the second allocator is processed in checkPostStmt().
266 State = State->remove<AllocatedData>(V);
267 ExplodedNode *N = C.generateNonFatalErrorNode(State);
268 if (!N)
269 return;
270 unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
271 auto Report = std::make_unique<PathSensitiveBugReport>(
272 BT,
273 "Allocated data should be released before another call to "
274 "the allocator: missing a call to '" +
275 Twine(FunctionsToTrack[DIdx].Name) + "'.",
276 N);
277 Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(V));
278 Report->addRange(ArgExpr->getSourceRange());
279 Report->markInteresting(AS->Region);
280 C.emitReport(std::move(Report));
281 }
282 return;
283 }
284
285 // Is it a call to one of deallocator functions?
286 idx = getTrackedFunctionIndex(funName, false);
287 if (idx == InvalidIdx)
288 return;
289
290 unsigned paramIdx = FunctionsToTrack[idx].Param;
291 if (CE->getNumArgs() <= paramIdx)
292 return;
293
294 // Check the argument to the deallocator.
295 const Expr *ArgExpr = CE->getArg(paramIdx);
296 SVal ArgSVal = C.getSVal(ArgExpr);
297
298 // Undef is reported by another checker.
299 if (ArgSVal.isUndef())
300 return;
301
302 SymbolRef ArgSM = ArgSVal.getAsLocSymbol();
303
304 // If the argument is coming from the heap, globals, or unknown, do not
305 // report it.
306 bool RegionArgIsBad = false;
307 if (!ArgSM) {
309 return;
310 RegionArgIsBad = true;
311 }
312
313 // Is the argument to the call being tracked?
314 const AllocationState *AS = State->get<AllocatedData>(ArgSM);
315 if (!AS)
316 return;
317
318 // TODO: We might want to report double free here.
319 // (that would involve tracking all the freed symbols in the checker state).
320 if (RegionArgIsBad) {
321 // It is possible that this is a false positive - the argument might
322 // have entered as an enclosing function parameter.
323 if (isEnclosingFunctionParam(ArgExpr))
324 return;
325
326 ExplodedNode *N = C.generateNonFatalErrorNode(State);
327 if (!N)
328 return;
329 auto Report = std::make_unique<PathSensitiveBugReport>(
330 BT, "Trying to free data which has not been allocated.", N);
331 Report->addRange(ArgExpr->getSourceRange());
332 if (AS)
333 Report->markInteresting(AS->Region);
334 C.emitReport(std::move(Report));
335 return;
336 }
337
338 // Process functions which might deallocate.
339 if (FunctionsToTrack[idx].Kind == PossibleAPI) {
340
341 if (funName == "CFStringCreateWithBytesNoCopy") {
342 const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts();
343 // NULL ~ default deallocator, so warn.
344 if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(),
346 const AllocationPair AP = std::make_pair(ArgSM, AS);
347 generateDeallocatorMismatchReport(AP, ArgExpr, C);
348 return;
349 }
350 // One of the default allocators, so warn.
351 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) {
352 StringRef DeallocatorName = DE->getFoundDecl()->getName();
353 if (DeallocatorName == "kCFAllocatorDefault" ||
354 DeallocatorName == "kCFAllocatorSystemDefault" ||
355 DeallocatorName == "kCFAllocatorMalloc") {
356 const AllocationPair AP = std::make_pair(ArgSM, AS);
357 generateDeallocatorMismatchReport(AP, ArgExpr, C);
358 return;
359 }
360 // If kCFAllocatorNull, which does not deallocate, we still have to
361 // find the deallocator.
362 if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
363 return;
364 }
365 // In all other cases, assume the user supplied a correct deallocator
366 // that will free memory so stop tracking.
367 State = State->remove<AllocatedData>(ArgSM);
368 C.addTransition(State);
369 return;
370 }
371
372 llvm_unreachable("We know of no other possible APIs.");
373 }
374
375 // The call is deallocating a value we previously allocated, so remove it
376 // from the next state.
377 State = State->remove<AllocatedData>(ArgSM);
378
379 // Check if the proper deallocator is used.
380 unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
381 if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) {
382 const AllocationPair AP = std::make_pair(ArgSM, AS);
383 generateDeallocatorMismatchReport(AP, ArgExpr, C);
384 return;
385 }
386
387 C.addTransition(State);
388}
389
390void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
391 CheckerContext &C) const {
392 ProgramStateRef State = C.getState();
393 const FunctionDecl *FD = C.getCalleeDecl(CE);
394 if (!FD || FD->getKind() != Decl::Function)
395 return;
396
397 StringRef funName = C.getCalleeName(FD);
398
399 // If a value has been allocated, add it to the set for tracking.
400 unsigned idx = getTrackedFunctionIndex(funName, true);
401 if (idx == InvalidIdx)
402 return;
403
404 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
405 // If the argument entered as an enclosing function parameter, skip it to
406 // avoid false positives.
407 if (isEnclosingFunctionParam(ArgExpr) &&
408 C.getStackFrame()->getParent() == nullptr)
409 return;
410
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
420 // The call return value symbol should stay alive for as long as the
421 // allocated value symbol, since our diagnostics depend on the value
422 // returned by the call. Ex: Data should only be freed if noErr was
423 // returned during allocation.)
424 SymbolRef RetStatusSymbol = C.getSVal(CE).getAsSymbol();
425 C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol);
426
427 // Track the allocated value in the checker state.
428 State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx,
429 RetStatusSymbol));
430 assert(State);
431 C.addTransition(State);
432 }
433}
434
435// TODO: This logic is the same as in Malloc checker.
436const ExplodedNode *
437MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
438 SymbolRef Sym,
439 CheckerContext &C) const {
440 const StackFrame *LeakStackFrame = N->getStackFrame();
441 // Walk the ExplodedGraph backwards and find the first node that referred to
442 // the tracked symbol.
443 const ExplodedNode *AllocNode = N;
444
445 while (N) {
446 if (!N->getState()->get<AllocatedData>(Sym))
447 break;
448 // Allocation node, is the last node in the current or parent context in
449 // which the symbol was tracked.
450 const StackFrame *NSF = N->getStackFrame();
451 if (NSF == LeakStackFrame || NSF->isParentOf(LeakStackFrame))
452 AllocNode = N;
453 N = N->pred_empty() ? nullptr : *(N->pred_begin());
454 }
455
456 return AllocNode;
457}
458
459std::unique_ptr<PathSensitiveBugReport>
460MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
461 const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const {
462 const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
463
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 = AllocNode->getStmtForDiagnostics();
470
471 if (AllocStmt)
472 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
473 AllocStmt, C.getSourceManager(), AllocNode->getStackFrame());
474
475 auto Report = std::make_unique<PathSensitiveBugReport>(
476 BT,
477 "Allocated data is not released: missing a call to '" +
478 Twine(FunctionsToTrack[FI.DeallocatorIdx].Name) + "'.",
479 N, LocUsedForUniqueing, AllocNode->getStackFrame()->getDecl());
480
481 Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
482 markInteresting(Report.get(), AP);
483 return Report;
484}
485
486/// If the return symbol is assumed to be error, remove the allocated info
487/// from consideration.
488ProgramStateRef MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State,
489 SVal Cond,
490 bool Assumption) const {
491 AllocatedDataTy AMap = State->get<AllocatedData>();
492 if (AMap.isEmpty())
493 return State;
494
495 auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymbol());
496 if (!CondBSE)
497 return State;
498 BinaryOperator::Opcode OpCode = CondBSE->getOpcode();
499 if (OpCode != BO_EQ && OpCode != BO_NE)
500 return State;
501
502 // Match for a restricted set of patterns for cmparison of error codes.
503 // Note, the comparisons of type '0 == st' are transformed into SymIntExpr.
504 SymbolRef ReturnSymbol = nullptr;
505 if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) {
506 const llvm::APInt &RHS = SIE->getRHS();
507 bool ErrorIsReturned = (OpCode == BO_EQ && RHS != NoErr) ||
508 (OpCode == BO_NE && RHS == NoErr);
509 if (!Assumption)
510 ErrorIsReturned = !ErrorIsReturned;
511 if (ErrorIsReturned)
512 ReturnSymbol = SIE->getLHS();
513 }
514
515 if (ReturnSymbol)
516 for (auto [Sym, AllocState] : AMap) {
517 if (ReturnSymbol == AllocState.Region)
518 State = State->remove<AllocatedData>(Sym);
519 }
520
521 return State;
522}
523
524void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
525 CheckerContext &C) const {
526 ProgramStateRef State = C.getState();
527 AllocatedDataTy AMap = State->get<AllocatedData>();
528 if (AMap.isEmpty())
529 return;
530
531 bool Changed = false;
532 AllocationPairVec Errors;
533 for (const auto &[Sym, AllocState] : AMap) {
534 if (!SR.isDead(Sym))
535 continue;
536
537 Changed = true;
538 State = State->remove<AllocatedData>(Sym);
539 // If the allocated symbol is null do not report.
540 ConstraintManager &CMgr = State->getConstraintManager();
541 ConditionTruthVal AllocFailed = CMgr.isNull(State, Sym);
542 if (AllocFailed.isConstrainedTrue())
543 continue;
544 Errors.push_back(std::make_pair(Sym, &AllocState));
545 }
546 if (!Changed) {
547 // Generate the new, cleaned up state.
548 C.addTransition(State);
549 return;
550 }
551
552 ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
553 if (!N)
554 return;
555
556 // Generate the error reports.
557 for (const auto &P : Errors)
558 C.emitReport(generateAllocatedDataNotReleasedReport(P, N, C));
559
560 // Generate the new, cleaned up state.
561 C.addTransition(State, N);
562}
563
564ProgramStateRef MacOSKeychainAPIChecker::checkPointerEscape(
565 ProgramStateRef State, const InvalidatedSymbols &Escaped,
566 const CallEvent *Call, PointerEscapeKind Kind) const {
567 // FIXME: This branch doesn't make any sense at all, but it is an overfitted
568 // replacement for a previous overfitted code that was making even less sense.
569 if (!Call || Call->getDecl())
570 return State;
571
572 for (auto I : State->get<AllocatedData>()) {
573 SymbolRef Sym = I.first;
574 if (Escaped.count(Sym))
575 State = State->remove<AllocatedData>(Sym);
576
577 // This checker is special. Most checkers in fact only track symbols of
578 // SymbolConjured type, eg. symbols returned from functions such as
579 // malloc(). This checker tracks symbols returned as out-parameters.
580 //
581 // When a function is evaluated conservatively, the out-parameter's pointee
582 // base region gets invalidated with a SymbolConjured. If the base region is
583 // larger than the region we're interested in, the value we're interested in
584 // would be SymbolDerived based on that SymbolConjured. However, such
585 // SymbolDerived will never be listed in the Escaped set when the base
586 // region is invalidated because ExprEngine doesn't know which symbols
587 // were derived from a given symbol, while there can be infinitely many
588 // valid symbols derived from any given symbol.
589 //
590 // Hence the extra boilerplate: remove the derived symbol when its parent
591 // symbol escapes.
592 //
593 if (const auto *SD = dyn_cast<SymbolDerived>(Sym)) {
594 SymbolRef ParentSym = SD->getParentSymbol();
595 if (Escaped.count(ParentSym))
596 State = State->remove<AllocatedData>(Sym);
597 }
598 }
599 return State;
600}
601
603MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
604 const ExplodedNode *N, BugReporterContext &BRC,
605 PathSensitiveBugReport &BR) {
606 const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
607 if (!AS)
608 return nullptr;
609 const AllocationState *ASPrev =
610 N->getFirstPred()->getState()->get<AllocatedData>(Sym);
611 if (ASPrev)
612 return nullptr;
613
614 // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
615 // allocation site.
616 const CallExpr *CE =
617 cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
618 const FunctionDecl *funDecl = CE->getDirectCallee();
619 assert(funDecl && "We do not support indirect function calls as of now.");
620 StringRef funName = funDecl->getName();
621
622 // Get the expression of the corresponding argument.
623 unsigned Idx = getTrackedFunctionIndex(funName, true);
624 assert(Idx != InvalidIdx && "This should be a call to an allocator.");
625 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param);
626 PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(),
627 N->getStackFrame());
628 return std::make_shared<PathDiagnosticEventPiece>(Pos,
629 "Data is allocated here.");
630}
631
632void MacOSKeychainAPIChecker::printState(raw_ostream &Out,
633 ProgramStateRef State,
634 const char *NL,
635 const char *Sep) const {
636
637 AllocatedDataTy AMap = State->get<AllocatedData>();
638
639 if (!AMap.isEmpty()) {
640 Out << Sep << "KeychainAPIChecker :" << NL;
641 for (SymbolRef Sym : llvm::make_first_range(AMap)) {
642 Sym->dumpToStream(Out);
643 }
644 }
645}
646
647
648void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
649 mgr.registerChecker<MacOSKeychainAPIChecker>();
650}
651
652bool ento::shouldRegisterMacOSKeychainAPIChecker(const CheckerManager &mgr) {
653 return true;
654}
#define V(N, I)
#define X(type, name)
Definition Value.h:97
static bool isBadDeallocationArgument(const MemRegion *Arg)
static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C)
Given the address expression, retrieve the value it's pointing to.
#define SM(sm)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
BinaryOperatorKind Opcode
Definition Expr.h:4049
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
Kind getKind() const
Definition DeclBase.h:450
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3104
@ NPC_ValueDependentIsNotNull
Specifies that a value-dependent expression should be considered to never be a null pointer constant.
Definition Expr.h:841
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:4077
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.
bool isParentOf(const StackFrame *SF) const
const Decl * getDecl() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
const SourceManager & getSourceManager() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:565
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:97
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:57
bool isUndef() const
Definition SVals.h:113
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:88
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition SVals.cpp:67
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
virtual void dumpToStream(raw_ostream &os) const
Definition SymExpr.h:81
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:50
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition CallGraph.h:207
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
Expr * Cond
};
U cast(CodeGen::Address addr)
Definition Address.h:327