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 15 #include "ClangSACheckers.h" 16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.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/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 eval::Assume> { 33 mutable std::unique_ptr<BugType> BT; 34 35 public: 36 /// AllocationState is a part of the checker specific state together with the 37 /// MemRegion corresponding to the allocated data. 38 struct AllocationState { 39 /// The index of the allocator function. 40 unsigned int AllocatorIdx; 41 SymbolRef Region; 42 43 AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) : 44 AllocatorIdx(Idx), 45 Region(R) {} 46 47 bool operator==(const AllocationState &X) const { 48 return (AllocatorIdx == X.AllocatorIdx && 49 Region == X.Region); 50 } 51 52 void Profile(llvm::FoldingSetNodeID &ID) const { 53 ID.AddInteger(AllocatorIdx); 54 ID.AddPointer(Region); 55 } 56 }; 57 58 void checkPreStmt(const CallExpr *S, CheckerContext &C) const; 59 void checkPostStmt(const CallExpr *S, CheckerContext &C) const; 60 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 61 ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, 62 bool Assumption) const; 63 void printState(raw_ostream &Out, ProgramStateRef State, 64 const char *NL, const char *Sep) const; 65 66 private: 67 typedef std::pair<SymbolRef, const AllocationState*> AllocationPair; 68 typedef SmallVector<AllocationPair, 2> AllocationPairVec; 69 70 enum APIKind { 71 /// Denotes functions tracked by this checker. 72 ValidAPI = 0, 73 /// The functions commonly/mistakenly used in place of the given API. 74 ErrorAPI = 1, 75 /// The functions which may allocate the data. These are tracked to reduce 76 /// the false alarm rate. 77 PossibleAPI = 2 78 }; 79 /// Stores the information about the allocator and deallocator functions - 80 /// these are the functions the checker is tracking. 81 struct ADFunctionInfo { 82 const char* Name; 83 unsigned int Param; 84 unsigned int DeallocatorIdx; 85 APIKind Kind; 86 }; 87 static const unsigned InvalidIdx = 100000; 88 static const unsigned FunctionsToTrackSize = 8; 89 static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize]; 90 /// The value, which represents no error return value for allocator functions. 91 static const unsigned NoErr = 0; 92 93 /// Given the function name, returns the index of the allocator/deallocator 94 /// function. 95 static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator); 96 97 inline void initBugType() const { 98 if (!BT) 99 BT.reset(new BugType(this, "Improper use of SecKeychain API", 100 "API Misuse (Apple)")); 101 } 102 103 void generateDeallocatorMismatchReport(const AllocationPair &AP, 104 const Expr *ArgExpr, 105 CheckerContext &C) const; 106 107 /// Find the allocation site for Sym on the path leading to the node N. 108 const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym, 109 CheckerContext &C) const; 110 111 std::unique_ptr<BugReport> generateAllocatedDataNotReleasedReport( 112 const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const; 113 114 /// Mark an AllocationPair interesting for diagnostic reporting. 115 void markInteresting(BugReport *R, const AllocationPair &AP) const { 116 R->markInteresting(AP.first); 117 R->markInteresting(AP.second->Region); 118 } 119 120 /// The bug visitor which allows us to print extra diagnostics along the 121 /// BugReport path. For example, showing the allocation site of the leaked 122 /// region. 123 class SecKeychainBugVisitor : public BugReporterVisitor { 124 protected: 125 // The allocated region symbol tracked by the main analysis. 126 SymbolRef Sym; 127 128 public: 129 SecKeychainBugVisitor(SymbolRef S) : Sym(S) {} 130 131 void Profile(llvm::FoldingSetNodeID &ID) const override { 132 static int X = 0; 133 ID.AddPointer(&X); 134 ID.AddPointer(Sym); 135 } 136 137 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 138 const ExplodedNode *PrevN, 139 BugReporterContext &BRC, 140 BugReport &BR) override; 141 }; 142 }; 143 } 144 145 /// ProgramState traits to store the currently allocated (and not yet freed) 146 /// symbols. This is a map from the allocated content symbol to the 147 /// corresponding AllocationState. 148 REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, 149 SymbolRef, 150 MacOSKeychainAPIChecker::AllocationState) 151 152 static bool isEnclosingFunctionParam(const Expr *E) { 153 E = E->IgnoreParenCasts(); 154 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { 155 const ValueDecl *VD = DRE->getDecl(); 156 if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD)) 157 return true; 158 } 159 return false; 160 } 161 162 const MacOSKeychainAPIChecker::ADFunctionInfo 163 MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = { 164 {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0 165 {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1 166 {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2 167 {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3 168 {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4 169 {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5 170 {"free", 0, InvalidIdx, ErrorAPI}, // 6 171 {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7 172 }; 173 174 unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, 175 bool IsAllocator) { 176 for (unsigned I = 0; I < FunctionsToTrackSize; ++I) { 177 ADFunctionInfo FI = FunctionsToTrack[I]; 178 if (FI.Name != Name) 179 continue; 180 // Make sure the function is of the right type (allocator vs deallocator). 181 if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx)) 182 return InvalidIdx; 183 if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx)) 184 return InvalidIdx; 185 186 return I; 187 } 188 // The function is not tracked. 189 return InvalidIdx; 190 } 191 192 static bool isBadDeallocationArgument(const MemRegion *Arg) { 193 if (!Arg) 194 return false; 195 return isa<AllocaRegion>(Arg) || isa<BlockDataRegion>(Arg) || 196 isa<TypedRegion>(Arg); 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. 201 static SymbolRef getAsPointeeSymbol(const Expr *Expr, 202 CheckerContext &C) { 203 ProgramStateRef State = C.getState(); 204 SVal ArgV = C.getSVal(Expr); 205 206 if (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. 217 void 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 initBugType(); 228 SmallString<80> sbuf; 229 llvm::raw_svector_ostream os(sbuf); 230 unsigned int PDeallocIdx = 231 FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx; 232 233 os << "Deallocator doesn't match the allocator: '" 234 << FunctionsToTrack[PDeallocIdx].Name << "' should be used."; 235 auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N); 236 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first)); 237 Report->addRange(ArgExpr->getSourceRange()); 238 markInteresting(Report.get(), AP); 239 C.emitReport(std::move(Report)); 240 } 241 242 void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, 243 CheckerContext &C) const { 244 unsigned idx = InvalidIdx; 245 ProgramStateRef State = C.getState(); 246 247 const FunctionDecl *FD = C.getCalleeDecl(CE); 248 if (!FD || FD->getKind() != Decl::Function) 249 return; 250 251 StringRef funName = C.getCalleeName(FD); 252 if (funName.empty()) 253 return; 254 255 // If it is a call to an allocator function, it could be a double allocation. 256 idx = getTrackedFunctionIndex(funName, true); 257 if (idx != InvalidIdx) { 258 unsigned paramIdx = FunctionsToTrack[idx].Param; 259 if (CE->getNumArgs() <= paramIdx) 260 return; 261 262 const Expr *ArgExpr = CE->getArg(paramIdx); 263 if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) 264 if (const AllocationState *AS = State->get<AllocatedData>(V)) { 265 // Remove the value from the state. The new symbol will be added for 266 // tracking when the second allocator is processed in checkPostStmt(). 267 State = State->remove<AllocatedData>(V); 268 ExplodedNode *N = C.generateNonFatalErrorNode(State); 269 if (!N) 270 return; 271 initBugType(); 272 SmallString<128> sbuf; 273 llvm::raw_svector_ostream os(sbuf); 274 unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 275 os << "Allocated data should be released before another call to " 276 << "the allocator: missing a call to '" 277 << FunctionsToTrack[DIdx].Name 278 << "'."; 279 auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N); 280 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V)); 281 Report->addRange(ArgExpr->getSourceRange()); 282 Report->markInteresting(AS->Region); 283 C.emitReport(std::move(Report)); 284 } 285 return; 286 } 287 288 // Is it a call to one of deallocator functions? 289 idx = getTrackedFunctionIndex(funName, false); 290 if (idx == InvalidIdx) 291 return; 292 293 unsigned paramIdx = FunctionsToTrack[idx].Param; 294 if (CE->getNumArgs() <= paramIdx) 295 return; 296 297 // Check the argument to the deallocator. 298 const Expr *ArgExpr = CE->getArg(paramIdx); 299 SVal ArgSVal = C.getSVal(ArgExpr); 300 301 // Undef is reported by another checker. 302 if (ArgSVal.isUndef()) 303 return; 304 305 SymbolRef ArgSM = ArgSVal.getAsLocSymbol(); 306 307 // If the argument is coming from the heap, globals, or unknown, do not 308 // report it. 309 bool RegionArgIsBad = false; 310 if (!ArgSM) { 311 if (!isBadDeallocationArgument(ArgSVal.getAsRegion())) 312 return; 313 RegionArgIsBad = true; 314 } 315 316 // Is the argument to the call being tracked? 317 const AllocationState *AS = State->get<AllocatedData>(ArgSM); 318 if (!AS) 319 return; 320 321 // TODO: We might want to report double free here. 322 // (that would involve tracking all the freed symbols in the checker state). 323 if (RegionArgIsBad) { 324 // It is possible that this is a false positive - the argument might 325 // have entered as an enclosing function parameter. 326 if (isEnclosingFunctionParam(ArgExpr)) 327 return; 328 329 ExplodedNode *N = C.generateNonFatalErrorNode(State); 330 if (!N) 331 return; 332 initBugType(); 333 auto Report = llvm::make_unique<BugReport>( 334 *BT, "Trying to free data which has not been allocated.", N); 335 Report->addRange(ArgExpr->getSourceRange()); 336 if (AS) 337 Report->markInteresting(AS->Region); 338 C.emitReport(std::move(Report)); 339 return; 340 } 341 342 // Process functions which might deallocate. 343 if (FunctionsToTrack[idx].Kind == PossibleAPI) { 344 345 if (funName == "CFStringCreateWithBytesNoCopy") { 346 const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts(); 347 // NULL ~ default deallocator, so warn. 348 if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(), 349 Expr::NPC_ValueDependentIsNotNull)) { 350 const AllocationPair AP = std::make_pair(ArgSM, AS); 351 generateDeallocatorMismatchReport(AP, ArgExpr, C); 352 return; 353 } 354 // One of the default allocators, so warn. 355 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) { 356 StringRef DeallocatorName = DE->getFoundDecl()->getName(); 357 if (DeallocatorName == "kCFAllocatorDefault" || 358 DeallocatorName == "kCFAllocatorSystemDefault" || 359 DeallocatorName == "kCFAllocatorMalloc") { 360 const AllocationPair AP = std::make_pair(ArgSM, AS); 361 generateDeallocatorMismatchReport(AP, ArgExpr, C); 362 return; 363 } 364 // If kCFAllocatorNull, which does not deallocate, we still have to 365 // find the deallocator. 366 if (DE->getFoundDecl()->getName() == "kCFAllocatorNull") 367 return; 368 } 369 // In all other cases, assume the user supplied a correct deallocator 370 // that will free memory so stop tracking. 371 State = State->remove<AllocatedData>(ArgSM); 372 C.addTransition(State); 373 return; 374 } 375 376 llvm_unreachable("We know of no other possible APIs."); 377 } 378 379 // The call is deallocating a value we previously allocated, so remove it 380 // from the next state. 381 State = State->remove<AllocatedData>(ArgSM); 382 383 // Check if the proper deallocator is used. 384 unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 385 if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) { 386 const AllocationPair AP = std::make_pair(ArgSM, AS); 387 generateDeallocatorMismatchReport(AP, ArgExpr, C); 388 return; 389 } 390 391 C.addTransition(State); 392 } 393 394 void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, 395 CheckerContext &C) const { 396 ProgramStateRef State = C.getState(); 397 const FunctionDecl *FD = C.getCalleeDecl(CE); 398 if (!FD || FD->getKind() != Decl::Function) 399 return; 400 401 StringRef funName = C.getCalleeName(FD); 402 403 // If a value has been allocated, add it to the set for tracking. 404 unsigned idx = getTrackedFunctionIndex(funName, true); 405 if (idx == InvalidIdx) 406 return; 407 408 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 409 // If the argument entered as an enclosing function parameter, skip it to 410 // avoid false positives. 411 if (isEnclosingFunctionParam(ArgExpr) && 412 C.getLocationContext()->getParent() == nullptr) 413 return; 414 415 if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { 416 // If the argument points to something that's not a symbolic region, it 417 // can be: 418 // - unknown (cannot reason about it) 419 // - undefined (already reported by other checker) 420 // - constant (null - should not be tracked, 421 // other constant will generate a compiler warning) 422 // - goto (should be reported by other checker) 423 424 // The call return value symbol should stay alive for as long as the 425 // allocated value symbol, since our diagnostics depend on the value 426 // returned by the call. Ex: Data should only be freed if noErr was 427 // returned during allocation.) 428 SymbolRef RetStatusSymbol = C.getSVal(CE).getAsSymbol(); 429 C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); 430 431 // Track the allocated value in the checker state. 432 State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, 433 RetStatusSymbol)); 434 assert(State); 435 C.addTransition(State); 436 } 437 } 438 439 // TODO: This logic is the same as in Malloc checker. 440 const ExplodedNode * 441 MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N, 442 SymbolRef Sym, 443 CheckerContext &C) const { 444 const LocationContext *LeakContext = N->getLocationContext(); 445 // Walk the ExplodedGraph backwards and find the first node that referred to 446 // the tracked symbol. 447 const ExplodedNode *AllocNode = N; 448 449 while (N) { 450 if (!N->getState()->get<AllocatedData>(Sym)) 451 break; 452 // Allocation node, is the last node in the current or parent context in 453 // which the symbol was tracked. 454 const LocationContext *NContext = N->getLocationContext(); 455 if (NContext == LeakContext || 456 NContext->isParentOf(LeakContext)) 457 AllocNode = N; 458 N = N->pred_empty() ? nullptr : *(N->pred_begin()); 459 } 460 461 return AllocNode; 462 } 463 464 std::unique_ptr<BugReport> 465 MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport( 466 const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const { 467 const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx]; 468 initBugType(); 469 SmallString<70> sbuf; 470 llvm::raw_svector_ostream os(sbuf); 471 os << "Allocated data is not released: missing a call to '" 472 << FunctionsToTrack[FI.DeallocatorIdx].Name << "'."; 473 474 // Most bug reports are cached at the location where they occurred. 475 // With leaks, we want to unique them by the location where they were 476 // allocated, and only report a single path. 477 PathDiagnosticLocation LocUsedForUniqueing; 478 const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C); 479 const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); 480 481 if (AllocStmt) 482 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt, 483 C.getSourceManager(), 484 AllocNode->getLocationContext()); 485 486 auto Report = 487 llvm::make_unique<BugReport>(*BT, os.str(), N, LocUsedForUniqueing, 488 AllocNode->getLocationContext()->getDecl()); 489 490 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first)); 491 markInteresting(Report.get(), AP); 492 return Report; 493 } 494 495 /// If the return symbol is assumed to be error, remove the allocated info 496 /// from consideration. 497 ProgramStateRef MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State, 498 SVal Cond, 499 bool Assumption) const { 500 AllocatedDataTy AMap = State->get<AllocatedData>(); 501 if (AMap.isEmpty()) 502 return State; 503 504 auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymExpr()); 505 if (!CondBSE) 506 return State; 507 BinaryOperator::Opcode OpCode = CondBSE->getOpcode(); 508 if (OpCode != BO_EQ && OpCode != BO_NE) 509 return State; 510 511 // Match for a restricted set of patterns for cmparison of error codes. 512 // Note, the comparisons of type '0 == st' are transformed into SymIntExpr. 513 SymbolRef ReturnSymbol = nullptr; 514 if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) { 515 const llvm::APInt &RHS = SIE->getRHS(); 516 bool ErrorIsReturned = (OpCode == BO_EQ && RHS != NoErr) || 517 (OpCode == BO_NE && RHS == NoErr); 518 if (!Assumption) 519 ErrorIsReturned = !ErrorIsReturned; 520 if (ErrorIsReturned) 521 ReturnSymbol = SIE->getLHS(); 522 } 523 524 if (ReturnSymbol) 525 for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) { 526 if (ReturnSymbol == I->second.Region) 527 State = State->remove<AllocatedData>(I->first); 528 } 529 530 return State; 531 } 532 533 void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, 534 CheckerContext &C) const { 535 ProgramStateRef State = C.getState(); 536 AllocatedDataTy AMap = State->get<AllocatedData>(); 537 if (AMap.isEmpty()) 538 return; 539 540 bool Changed = false; 541 AllocationPairVec Errors; 542 for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) { 543 if (!SR.isDead(I->first)) 544 continue; 545 546 Changed = true; 547 State = State->remove<AllocatedData>(I->first); 548 // If the allocated symbol is null do not report. 549 ConstraintManager &CMgr = State->getConstraintManager(); 550 ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey()); 551 if (AllocFailed.isConstrainedTrue()) 552 continue; 553 Errors.push_back(std::make_pair(I->first, &I->second)); 554 } 555 if (!Changed) { 556 // Generate the new, cleaned up state. 557 C.addTransition(State); 558 return; 559 } 560 561 static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak"); 562 ExplodedNode *N = C.generateNonFatalErrorNode(C.getState(), &Tag); 563 if (!N) 564 return; 565 566 // Generate the error reports. 567 for (const auto &P : Errors) 568 C.emitReport(generateAllocatedDataNotReleasedReport(P, N, C)); 569 570 // Generate the new, cleaned up state. 571 C.addTransition(State, N); 572 } 573 574 std::shared_ptr<PathDiagnosticPiece> 575 MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode( 576 const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, 577 BugReport &BR) { 578 const AllocationState *AS = N->getState()->get<AllocatedData>(Sym); 579 if (!AS) 580 return nullptr; 581 const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym); 582 if (ASPrev) 583 return nullptr; 584 585 // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the 586 // allocation site. 587 const CallExpr *CE = 588 cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt()); 589 const FunctionDecl *funDecl = CE->getDirectCallee(); 590 assert(funDecl && "We do not support indirect function calls as of now."); 591 StringRef funName = funDecl->getName(); 592 593 // Get the expression of the corresponding argument. 594 unsigned Idx = getTrackedFunctionIndex(funName, true); 595 assert(Idx != InvalidIdx && "This should be a call to an allocator."); 596 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param); 597 PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(), 598 N->getLocationContext()); 599 return std::make_shared<PathDiagnosticEventPiece>(Pos, 600 "Data is allocated here."); 601 } 602 603 void MacOSKeychainAPIChecker::printState(raw_ostream &Out, 604 ProgramStateRef State, 605 const char *NL, 606 const char *Sep) const { 607 608 AllocatedDataTy AMap = State->get<AllocatedData>(); 609 610 if (!AMap.isEmpty()) { 611 Out << Sep << "KeychainAPIChecker :" << NL; 612 for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) { 613 I.getKey()->dumpToStream(Out); 614 } 615 } 616 } 617 618 619 void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) { 620 mgr.registerChecker<MacOSKeychainAPIChecker>(); 621 } 622