1 //==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==//
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
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 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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/CallEvent.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
22 #include "llvm/ADT/STLExtras.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
27 using namespace clang
;
31 class MacOSKeychainAPIChecker
: public Checker
<check::PreStmt
<CallExpr
>,
32 check::PostStmt
<CallExpr
>,
36 mutable std::unique_ptr
<BugType
> BT
;
39 /// AllocationState is a part of the checker specific state together with the
40 /// MemRegion corresponding to the allocated data.
41 struct AllocationState
{
42 /// The index of the allocator function.
43 unsigned int AllocatorIdx
;
46 AllocationState(const Expr
*E
, unsigned int Idx
, SymbolRef R
) :
50 bool operator==(const AllocationState
&X
) const {
51 return (AllocatorIdx
== X
.AllocatorIdx
&&
55 void Profile(llvm::FoldingSetNodeID
&ID
) const {
56 ID
.AddInteger(AllocatorIdx
);
57 ID
.AddPointer(Region
);
61 void checkPreStmt(const CallExpr
*S
, CheckerContext
&C
) const;
62 void checkPostStmt(const CallExpr
*S
, CheckerContext
&C
) const;
63 void checkDeadSymbols(SymbolReaper
&SR
, CheckerContext
&C
) const;
64 ProgramStateRef
checkPointerEscape(ProgramStateRef State
,
65 const InvalidatedSymbols
&Escaped
,
66 const CallEvent
*Call
,
67 PointerEscapeKind Kind
) const;
68 ProgramStateRef
evalAssume(ProgramStateRef state
, SVal Cond
,
69 bool Assumption
) const;
70 void printState(raw_ostream
&Out
, ProgramStateRef State
,
71 const char *NL
, const char *Sep
) const override
;
74 typedef std::pair
<SymbolRef
, const AllocationState
*> AllocationPair
;
75 typedef SmallVector
<AllocationPair
, 2> AllocationPairVec
;
78 /// Denotes functions tracked by this checker.
80 /// The functions commonly/mistakenly used in place of the given API.
82 /// The functions which may allocate the data. These are tracked to reduce
83 /// the false alarm rate.
86 /// Stores the information about the allocator and deallocator functions -
87 /// these are the functions the checker is tracking.
88 struct ADFunctionInfo
{
91 unsigned int DeallocatorIdx
;
94 static const unsigned InvalidIdx
= 100000;
95 static const unsigned FunctionsToTrackSize
= 8;
96 static const ADFunctionInfo FunctionsToTrack
[FunctionsToTrackSize
];
97 /// The value, which represents no error return value for allocator functions.
98 static const unsigned NoErr
= 0;
100 /// Given the function name, returns the index of the allocator/deallocator
102 static unsigned getTrackedFunctionIndex(StringRef Name
, bool IsAllocator
);
104 inline void initBugType() const {
106 BT
.reset(new BugType(this, "Improper use of SecKeychain API",
107 "API Misuse (Apple)"));
110 void generateDeallocatorMismatchReport(const AllocationPair
&AP
,
112 CheckerContext
&C
) const;
114 /// Find the allocation site for Sym on the path leading to the node N.
115 const ExplodedNode
*getAllocationNode(const ExplodedNode
*N
, SymbolRef Sym
,
116 CheckerContext
&C
) const;
118 std::unique_ptr
<PathSensitiveBugReport
>
119 generateAllocatedDataNotReleasedReport(const AllocationPair
&AP
,
121 CheckerContext
&C
) const;
123 /// Mark an AllocationPair interesting for diagnostic reporting.
124 void markInteresting(PathSensitiveBugReport
*R
,
125 const AllocationPair
&AP
) const {
126 R
->markInteresting(AP
.first
);
127 R
->markInteresting(AP
.second
->Region
);
130 /// The bug visitor which allows us to print extra diagnostics along the
131 /// BugReport path. For example, showing the allocation site of the leaked
133 class SecKeychainBugVisitor
: public BugReporterVisitor
{
135 // The allocated region symbol tracked by the main analysis.
139 SecKeychainBugVisitor(SymbolRef S
) : Sym(S
) {}
141 void Profile(llvm::FoldingSetNodeID
&ID
) const override
{
147 PathDiagnosticPieceRef
VisitNode(const ExplodedNode
*N
,
148 BugReporterContext
&BRC
,
149 PathSensitiveBugReport
&BR
) override
;
154 /// ProgramState traits to store the currently allocated (and not yet freed)
155 /// symbols. This is a map from the allocated content symbol to the
156 /// corresponding AllocationState.
157 REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData
,
159 MacOSKeychainAPIChecker::AllocationState
)
161 static bool isEnclosingFunctionParam(const Expr
*E
) {
162 E
= E
->IgnoreParenCasts();
163 if (const DeclRefExpr
*DRE
= dyn_cast
<DeclRefExpr
>(E
)) {
164 const ValueDecl
*VD
= DRE
->getDecl();
165 if (isa
<ImplicitParamDecl
, ParmVarDecl
>(VD
))
171 const MacOSKeychainAPIChecker::ADFunctionInfo
172 MacOSKeychainAPIChecker::FunctionsToTrack
[FunctionsToTrackSize
] = {
173 {"SecKeychainItemCopyContent", 4, 3, ValidAPI
}, // 0
174 {"SecKeychainFindGenericPassword", 6, 3, ValidAPI
}, // 1
175 {"SecKeychainFindInternetPassword", 13, 3, ValidAPI
}, // 2
176 {"SecKeychainItemFreeContent", 1, InvalidIdx
, ValidAPI
}, // 3
177 {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI
}, // 4
178 {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx
, ValidAPI
}, // 5
179 {"free", 0, InvalidIdx
, ErrorAPI
}, // 6
180 {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx
, PossibleAPI
}, // 7
183 unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name
,
185 for (unsigned I
= 0; I
< FunctionsToTrackSize
; ++I
) {
186 ADFunctionInfo FI
= FunctionsToTrack
[I
];
189 // Make sure the function is of the right type (allocator vs deallocator).
190 if (IsAllocator
&& (FI
.DeallocatorIdx
== InvalidIdx
))
192 if (!IsAllocator
&& (FI
.DeallocatorIdx
!= InvalidIdx
))
197 // The function is not tracked.
201 static bool isBadDeallocationArgument(const MemRegion
*Arg
) {
204 return isa
<AllocaRegion
, BlockDataRegion
, TypedRegion
>(Arg
);
207 /// Given the address expression, retrieve the value it's pointing to. Assume
208 /// that value is itself an address, and return the corresponding symbol.
209 static SymbolRef
getAsPointeeSymbol(const Expr
*Expr
,
211 ProgramStateRef State
= C
.getState();
212 SVal ArgV
= C
.getSVal(Expr
);
214 if (std::optional
<loc::MemRegionVal
> X
= ArgV
.getAs
<loc::MemRegionVal
>()) {
215 StoreManager
& SM
= C
.getStoreManager();
216 SymbolRef sym
= SM
.getBinding(State
->getStore(), *X
).getAsLocSymbol();
223 // Report deallocator mismatch. Remove the region from tracking - reporting a
224 // missing free error after this one is redundant.
225 void MacOSKeychainAPIChecker::
226 generateDeallocatorMismatchReport(const AllocationPair
&AP
,
228 CheckerContext
&C
) const {
229 ProgramStateRef State
= C
.getState();
230 State
= State
->remove
<AllocatedData
>(AP
.first
);
231 ExplodedNode
*N
= C
.generateNonFatalErrorNode(State
);
236 SmallString
<80> sbuf
;
237 llvm::raw_svector_ostream
os(sbuf
);
238 unsigned int PDeallocIdx
=
239 FunctionsToTrack
[AP
.second
->AllocatorIdx
].DeallocatorIdx
;
241 os
<< "Deallocator doesn't match the allocator: '"
242 << FunctionsToTrack
[PDeallocIdx
].Name
<< "' should be used.";
243 auto Report
= std::make_unique
<PathSensitiveBugReport
>(*BT
, os
.str(), N
);
244 Report
->addVisitor(std::make_unique
<SecKeychainBugVisitor
>(AP
.first
));
245 Report
->addRange(ArgExpr
->getSourceRange());
246 markInteresting(Report
.get(), AP
);
247 C
.emitReport(std::move(Report
));
250 void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr
*CE
,
251 CheckerContext
&C
) const {
252 unsigned idx
= InvalidIdx
;
253 ProgramStateRef State
= C
.getState();
255 const FunctionDecl
*FD
= C
.getCalleeDecl(CE
);
256 if (!FD
|| FD
->getKind() != Decl::Function
)
259 StringRef funName
= C
.getCalleeName(FD
);
263 // If it is a call to an allocator function, it could be a double allocation.
264 idx
= getTrackedFunctionIndex(funName
, true);
265 if (idx
!= InvalidIdx
) {
266 unsigned paramIdx
= FunctionsToTrack
[idx
].Param
;
267 if (CE
->getNumArgs() <= paramIdx
)
270 const Expr
*ArgExpr
= CE
->getArg(paramIdx
);
271 if (SymbolRef V
= getAsPointeeSymbol(ArgExpr
, C
))
272 if (const AllocationState
*AS
= State
->get
<AllocatedData
>(V
)) {
273 // Remove the value from the state. The new symbol will be added for
274 // tracking when the second allocator is processed in checkPostStmt().
275 State
= State
->remove
<AllocatedData
>(V
);
276 ExplodedNode
*N
= C
.generateNonFatalErrorNode(State
);
280 SmallString
<128> sbuf
;
281 llvm::raw_svector_ostream
os(sbuf
);
282 unsigned int DIdx
= FunctionsToTrack
[AS
->AllocatorIdx
].DeallocatorIdx
;
283 os
<< "Allocated data should be released before another call to "
284 << "the allocator: missing a call to '"
285 << FunctionsToTrack
[DIdx
].Name
288 std::make_unique
<PathSensitiveBugReport
>(*BT
, os
.str(), N
);
289 Report
->addVisitor(std::make_unique
<SecKeychainBugVisitor
>(V
));
290 Report
->addRange(ArgExpr
->getSourceRange());
291 Report
->markInteresting(AS
->Region
);
292 C
.emitReport(std::move(Report
));
297 // Is it a call to one of deallocator functions?
298 idx
= getTrackedFunctionIndex(funName
, false);
299 if (idx
== InvalidIdx
)
302 unsigned paramIdx
= FunctionsToTrack
[idx
].Param
;
303 if (CE
->getNumArgs() <= paramIdx
)
306 // Check the argument to the deallocator.
307 const Expr
*ArgExpr
= CE
->getArg(paramIdx
);
308 SVal ArgSVal
= C
.getSVal(ArgExpr
);
310 // Undef is reported by another checker.
311 if (ArgSVal
.isUndef())
314 SymbolRef ArgSM
= ArgSVal
.getAsLocSymbol();
316 // If the argument is coming from the heap, globals, or unknown, do not
318 bool RegionArgIsBad
= false;
320 if (!isBadDeallocationArgument(ArgSVal
.getAsRegion()))
322 RegionArgIsBad
= true;
325 // Is the argument to the call being tracked?
326 const AllocationState
*AS
= State
->get
<AllocatedData
>(ArgSM
);
330 // TODO: We might want to report double free here.
331 // (that would involve tracking all the freed symbols in the checker state).
332 if (RegionArgIsBad
) {
333 // It is possible that this is a false positive - the argument might
334 // have entered as an enclosing function parameter.
335 if (isEnclosingFunctionParam(ArgExpr
))
338 ExplodedNode
*N
= C
.generateNonFatalErrorNode(State
);
342 auto Report
= std::make_unique
<PathSensitiveBugReport
>(
343 *BT
, "Trying to free data which has not been allocated.", N
);
344 Report
->addRange(ArgExpr
->getSourceRange());
346 Report
->markInteresting(AS
->Region
);
347 C
.emitReport(std::move(Report
));
351 // Process functions which might deallocate.
352 if (FunctionsToTrack
[idx
].Kind
== PossibleAPI
) {
354 if (funName
== "CFStringCreateWithBytesNoCopy") {
355 const Expr
*DeallocatorExpr
= CE
->getArg(5)->IgnoreParenCasts();
356 // NULL ~ default deallocator, so warn.
357 if (DeallocatorExpr
->isNullPointerConstant(C
.getASTContext(),
358 Expr::NPC_ValueDependentIsNotNull
)) {
359 const AllocationPair AP
= std::make_pair(ArgSM
, AS
);
360 generateDeallocatorMismatchReport(AP
, ArgExpr
, C
);
363 // One of the default allocators, so warn.
364 if (const DeclRefExpr
*DE
= dyn_cast
<DeclRefExpr
>(DeallocatorExpr
)) {
365 StringRef DeallocatorName
= DE
->getFoundDecl()->getName();
366 if (DeallocatorName
== "kCFAllocatorDefault" ||
367 DeallocatorName
== "kCFAllocatorSystemDefault" ||
368 DeallocatorName
== "kCFAllocatorMalloc") {
369 const AllocationPair AP
= std::make_pair(ArgSM
, AS
);
370 generateDeallocatorMismatchReport(AP
, ArgExpr
, C
);
373 // If kCFAllocatorNull, which does not deallocate, we still have to
374 // find the deallocator.
375 if (DE
->getFoundDecl()->getName() == "kCFAllocatorNull")
378 // In all other cases, assume the user supplied a correct deallocator
379 // that will free memory so stop tracking.
380 State
= State
->remove
<AllocatedData
>(ArgSM
);
381 C
.addTransition(State
);
385 llvm_unreachable("We know of no other possible APIs.");
388 // The call is deallocating a value we previously allocated, so remove it
389 // from the next state.
390 State
= State
->remove
<AllocatedData
>(ArgSM
);
392 // Check if the proper deallocator is used.
393 unsigned int PDeallocIdx
= FunctionsToTrack
[AS
->AllocatorIdx
].DeallocatorIdx
;
394 if (PDeallocIdx
!= idx
|| (FunctionsToTrack
[idx
].Kind
== ErrorAPI
)) {
395 const AllocationPair AP
= std::make_pair(ArgSM
, AS
);
396 generateDeallocatorMismatchReport(AP
, ArgExpr
, C
);
400 C
.addTransition(State
);
403 void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr
*CE
,
404 CheckerContext
&C
) const {
405 ProgramStateRef State
= C
.getState();
406 const FunctionDecl
*FD
= C
.getCalleeDecl(CE
);
407 if (!FD
|| FD
->getKind() != Decl::Function
)
410 StringRef funName
= C
.getCalleeName(FD
);
412 // If a value has been allocated, add it to the set for tracking.
413 unsigned idx
= getTrackedFunctionIndex(funName
, true);
414 if (idx
== InvalidIdx
)
417 const Expr
*ArgExpr
= CE
->getArg(FunctionsToTrack
[idx
].Param
);
418 // If the argument entered as an enclosing function parameter, skip it to
419 // avoid false positives.
420 if (isEnclosingFunctionParam(ArgExpr
) &&
421 C
.getLocationContext()->getParent() == nullptr)
424 if (SymbolRef V
= getAsPointeeSymbol(ArgExpr
, C
)) {
425 // If the argument points to something that's not a symbolic region, it
427 // - unknown (cannot reason about it)
428 // - undefined (already reported by other checker)
429 // - constant (null - should not be tracked,
430 // other constant will generate a compiler warning)
431 // - goto (should be reported by other checker)
433 // The call return value symbol should stay alive for as long as the
434 // allocated value symbol, since our diagnostics depend on the value
435 // returned by the call. Ex: Data should only be freed if noErr was
436 // returned during allocation.)
437 SymbolRef RetStatusSymbol
= C
.getSVal(CE
).getAsSymbol();
438 C
.getSymbolManager().addSymbolDependency(V
, RetStatusSymbol
);
440 // Track the allocated value in the checker state.
441 State
= State
->set
<AllocatedData
>(V
, AllocationState(ArgExpr
, idx
,
444 C
.addTransition(State
);
448 // TODO: This logic is the same as in Malloc checker.
450 MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode
*N
,
452 CheckerContext
&C
) const {
453 const LocationContext
*LeakContext
= N
->getLocationContext();
454 // Walk the ExplodedGraph backwards and find the first node that referred to
455 // the tracked symbol.
456 const ExplodedNode
*AllocNode
= N
;
459 if (!N
->getState()->get
<AllocatedData
>(Sym
))
461 // Allocation node, is the last node in the current or parent context in
462 // which the symbol was tracked.
463 const LocationContext
*NContext
= N
->getLocationContext();
464 if (NContext
== LeakContext
||
465 NContext
->isParentOf(LeakContext
))
467 N
= N
->pred_empty() ? nullptr : *(N
->pred_begin());
473 std::unique_ptr
<PathSensitiveBugReport
>
474 MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
475 const AllocationPair
&AP
, ExplodedNode
*N
, CheckerContext
&C
) const {
476 const ADFunctionInfo
&FI
= FunctionsToTrack
[AP
.second
->AllocatorIdx
];
478 SmallString
<70> sbuf
;
479 llvm::raw_svector_ostream
os(sbuf
);
480 os
<< "Allocated data is not released: missing a call to '"
481 << FunctionsToTrack
[FI
.DeallocatorIdx
].Name
<< "'.";
483 // Most bug reports are cached at the location where they occurred.
484 // With leaks, we want to unique them by the location where they were
485 // allocated, and only report a single path.
486 PathDiagnosticLocation LocUsedForUniqueing
;
487 const ExplodedNode
*AllocNode
= getAllocationNode(N
, AP
.first
, C
);
488 const Stmt
*AllocStmt
= AllocNode
->getStmtForDiagnostics();
491 LocUsedForUniqueing
= PathDiagnosticLocation::createBegin(AllocStmt
,
492 C
.getSourceManager(),
493 AllocNode
->getLocationContext());
495 auto Report
= std::make_unique
<PathSensitiveBugReport
>(
496 *BT
, os
.str(), N
, LocUsedForUniqueing
,
497 AllocNode
->getLocationContext()->getDecl());
499 Report
->addVisitor(std::make_unique
<SecKeychainBugVisitor
>(AP
.first
));
500 markInteresting(Report
.get(), AP
);
504 /// If the return symbol is assumed to be error, remove the allocated info
505 /// from consideration.
506 ProgramStateRef
MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State
,
508 bool Assumption
) const {
509 AllocatedDataTy AMap
= State
->get
<AllocatedData
>();
513 auto *CondBSE
= dyn_cast_or_null
<BinarySymExpr
>(Cond
.getAsSymbol());
516 BinaryOperator::Opcode OpCode
= CondBSE
->getOpcode();
517 if (OpCode
!= BO_EQ
&& OpCode
!= BO_NE
)
520 // Match for a restricted set of patterns for cmparison of error codes.
521 // Note, the comparisons of type '0 == st' are transformed into SymIntExpr.
522 SymbolRef ReturnSymbol
= nullptr;
523 if (auto *SIE
= dyn_cast
<SymIntExpr
>(CondBSE
)) {
524 const llvm::APInt
&RHS
= SIE
->getRHS();
525 bool ErrorIsReturned
= (OpCode
== BO_EQ
&& RHS
!= NoErr
) ||
526 (OpCode
== BO_NE
&& RHS
== NoErr
);
528 ErrorIsReturned
= !ErrorIsReturned
;
530 ReturnSymbol
= SIE
->getLHS();
534 for (auto [Sym
, AllocState
] : AMap
) {
535 if (ReturnSymbol
== AllocState
.Region
)
536 State
= State
->remove
<AllocatedData
>(Sym
);
542 void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper
&SR
,
543 CheckerContext
&C
) const {
544 ProgramStateRef State
= C
.getState();
545 AllocatedDataTy AMap
= State
->get
<AllocatedData
>();
549 bool Changed
= false;
550 AllocationPairVec Errors
;
551 for (const auto &[Sym
, AllocState
] : AMap
) {
556 State
= State
->remove
<AllocatedData
>(Sym
);
557 // If the allocated symbol is null do not report.
558 ConstraintManager
&CMgr
= State
->getConstraintManager();
559 ConditionTruthVal AllocFailed
= CMgr
.isNull(State
, Sym
);
560 if (AllocFailed
.isConstrainedTrue())
562 Errors
.push_back(std::make_pair(Sym
, &AllocState
));
565 // Generate the new, cleaned up state.
566 C
.addTransition(State
);
570 static CheckerProgramPointTag
Tag(this, "DeadSymbolsLeak");
571 ExplodedNode
*N
= C
.generateNonFatalErrorNode(C
.getState(), &Tag
);
575 // Generate the error reports.
576 for (const auto &P
: Errors
)
577 C
.emitReport(generateAllocatedDataNotReleasedReport(P
, N
, C
));
579 // Generate the new, cleaned up state.
580 C
.addTransition(State
, N
);
583 ProgramStateRef
MacOSKeychainAPIChecker::checkPointerEscape(
584 ProgramStateRef State
, const InvalidatedSymbols
&Escaped
,
585 const CallEvent
*Call
, PointerEscapeKind Kind
) const {
586 // FIXME: This branch doesn't make any sense at all, but it is an overfitted
587 // replacement for a previous overfitted code that was making even less sense.
588 if (!Call
|| Call
->getDecl())
591 for (auto I
: State
->get
<AllocatedData
>()) {
592 SymbolRef Sym
= I
.first
;
593 if (Escaped
.count(Sym
))
594 State
= State
->remove
<AllocatedData
>(Sym
);
596 // This checker is special. Most checkers in fact only track symbols of
597 // SymbolConjured type, eg. symbols returned from functions such as
598 // malloc(). This checker tracks symbols returned as out-parameters.
600 // When a function is evaluated conservatively, the out-parameter's pointee
601 // base region gets invalidated with a SymbolConjured. If the base region is
602 // larger than the region we're interested in, the value we're interested in
603 // would be SymbolDerived based on that SymbolConjured. However, such
604 // SymbolDerived will never be listed in the Escaped set when the base
605 // region is invalidated because ExprEngine doesn't know which symbols
606 // were derived from a given symbol, while there can be infinitely many
607 // valid symbols derived from any given symbol.
609 // Hence the extra boilerplate: remove the derived symbol when its parent
612 if (const auto *SD
= dyn_cast
<SymbolDerived
>(Sym
)) {
613 SymbolRef ParentSym
= SD
->getParentSymbol();
614 if (Escaped
.count(ParentSym
))
615 State
= State
->remove
<AllocatedData
>(Sym
);
621 PathDiagnosticPieceRef
622 MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
623 const ExplodedNode
*N
, BugReporterContext
&BRC
,
624 PathSensitiveBugReport
&BR
) {
625 const AllocationState
*AS
= N
->getState()->get
<AllocatedData
>(Sym
);
628 const AllocationState
*ASPrev
=
629 N
->getFirstPred()->getState()->get
<AllocatedData
>(Sym
);
633 // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
636 cast
<CallExpr
>(N
->getLocation().castAs
<StmtPoint
>().getStmt());
637 const FunctionDecl
*funDecl
= CE
->getDirectCallee();
638 assert(funDecl
&& "We do not support indirect function calls as of now.");
639 StringRef funName
= funDecl
->getName();
641 // Get the expression of the corresponding argument.
642 unsigned Idx
= getTrackedFunctionIndex(funName
, true);
643 assert(Idx
!= InvalidIdx
&& "This should be a call to an allocator.");
644 const Expr
*ArgExpr
= CE
->getArg(FunctionsToTrack
[Idx
].Param
);
645 PathDiagnosticLocation
Pos(ArgExpr
, BRC
.getSourceManager(),
646 N
->getLocationContext());
647 return std::make_shared
<PathDiagnosticEventPiece
>(Pos
,
648 "Data is allocated here.");
651 void MacOSKeychainAPIChecker::printState(raw_ostream
&Out
,
652 ProgramStateRef State
,
654 const char *Sep
) const {
656 AllocatedDataTy AMap
= State
->get
<AllocatedData
>();
658 if (!AMap
.isEmpty()) {
659 Out
<< Sep
<< "KeychainAPIChecker :" << NL
;
660 for (SymbolRef Sym
: llvm::make_first_range(AMap
)) {
661 Sym
->dumpToStream(Out
);
667 void ento::registerMacOSKeychainAPIChecker(CheckerManager
&mgr
) {
668 mgr
.registerChecker
<MacOSKeychainAPIChecker
>();
671 bool ento::shouldRegisterMacOSKeychainAPIChecker(const CheckerManager
&mgr
) {