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