clang API Documentation
00001 //==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // This checker flags misuses of KeyChainAPI. In particular, the password data 00010 // allocated/returned by SecKeychainItemCopyContent, 00011 // SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has 00012 // to be freed using a call to SecKeychainItemFreeContent. 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 00022 #include "llvm/ADT/SmallString.h" 00023 #include "llvm/Support/raw_ostream.h" 00024 00025 using namespace clang; 00026 using namespace ento; 00027 00028 namespace { 00029 class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>, 00030 check::PostStmt<CallExpr>, 00031 check::DeadSymbols> { 00032 mutable std::unique_ptr<BugType> BT; 00033 00034 public: 00035 /// AllocationState is a part of the checker specific state together with the 00036 /// MemRegion corresponding to the allocated data. 00037 struct AllocationState { 00038 /// The index of the allocator function. 00039 unsigned int AllocatorIdx; 00040 SymbolRef Region; 00041 00042 AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) : 00043 AllocatorIdx(Idx), 00044 Region(R) {} 00045 00046 bool operator==(const AllocationState &X) const { 00047 return (AllocatorIdx == X.AllocatorIdx && 00048 Region == X.Region); 00049 } 00050 00051 void Profile(llvm::FoldingSetNodeID &ID) const { 00052 ID.AddInteger(AllocatorIdx); 00053 ID.AddPointer(Region); 00054 } 00055 }; 00056 00057 void checkPreStmt(const CallExpr *S, CheckerContext &C) const; 00058 void checkPostStmt(const CallExpr *S, CheckerContext &C) const; 00059 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 00060 00061 private: 00062 typedef std::pair<SymbolRef, const AllocationState*> AllocationPair; 00063 typedef SmallVector<AllocationPair, 2> AllocationPairVec; 00064 00065 enum APIKind { 00066 /// Denotes functions tracked by this checker. 00067 ValidAPI = 0, 00068 /// The functions commonly/mistakenly used in place of the given API. 00069 ErrorAPI = 1, 00070 /// The functions which may allocate the data. These are tracked to reduce 00071 /// the false alarm rate. 00072 PossibleAPI = 2 00073 }; 00074 /// Stores the information about the allocator and deallocator functions - 00075 /// these are the functions the checker is tracking. 00076 struct ADFunctionInfo { 00077 const char* Name; 00078 unsigned int Param; 00079 unsigned int DeallocatorIdx; 00080 APIKind Kind; 00081 }; 00082 static const unsigned InvalidIdx = 100000; 00083 static const unsigned FunctionsToTrackSize = 8; 00084 static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize]; 00085 /// The value, which represents no error return value for allocator functions. 00086 static const unsigned NoErr = 0; 00087 00088 /// Given the function name, returns the index of the allocator/deallocator 00089 /// function. 00090 static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator); 00091 00092 inline void initBugType() const { 00093 if (!BT) 00094 BT.reset(new BugType(this, "Improper use of SecKeychain API", 00095 "API Misuse (Apple)")); 00096 } 00097 00098 void generateDeallocatorMismatchReport(const AllocationPair &AP, 00099 const Expr *ArgExpr, 00100 CheckerContext &C) const; 00101 00102 /// Find the allocation site for Sym on the path leading to the node N. 00103 const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym, 00104 CheckerContext &C) const; 00105 00106 BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP, 00107 ExplodedNode *N, 00108 CheckerContext &C) const; 00109 00110 /// Check if RetSym evaluates to an error value in the current state. 00111 bool definitelyReturnedError(SymbolRef RetSym, 00112 ProgramStateRef State, 00113 SValBuilder &Builder, 00114 bool noError = false) const; 00115 00116 /// Check if RetSym evaluates to a NoErr value in the current state. 00117 bool definitelyDidnotReturnError(SymbolRef RetSym, 00118 ProgramStateRef State, 00119 SValBuilder &Builder) const { 00120 return definitelyReturnedError(RetSym, State, Builder, true); 00121 } 00122 00123 /// Mark an AllocationPair interesting for diagnostic reporting. 00124 void markInteresting(BugReport *R, const AllocationPair &AP) const { 00125 R->markInteresting(AP.first); 00126 R->markInteresting(AP.second->Region); 00127 } 00128 00129 /// The bug visitor which allows us to print extra diagnostics along the 00130 /// BugReport path. For example, showing the allocation site of the leaked 00131 /// region. 00132 class SecKeychainBugVisitor 00133 : public BugReporterVisitorImpl<SecKeychainBugVisitor> { 00134 protected: 00135 // The allocated region symbol tracked by the main analysis. 00136 SymbolRef Sym; 00137 00138 public: 00139 SecKeychainBugVisitor(SymbolRef S) : Sym(S) {} 00140 virtual ~SecKeychainBugVisitor() {} 00141 00142 void Profile(llvm::FoldingSetNodeID &ID) const override { 00143 static int X = 0; 00144 ID.AddPointer(&X); 00145 ID.AddPointer(Sym); 00146 } 00147 00148 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 00149 const ExplodedNode *PrevN, 00150 BugReporterContext &BRC, 00151 BugReport &BR) override; 00152 }; 00153 }; 00154 } 00155 00156 /// ProgramState traits to store the currently allocated (and not yet freed) 00157 /// symbols. This is a map from the allocated content symbol to the 00158 /// corresponding AllocationState. 00159 REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, 00160 SymbolRef, 00161 MacOSKeychainAPIChecker::AllocationState) 00162 00163 static bool isEnclosingFunctionParam(const Expr *E) { 00164 E = E->IgnoreParenCasts(); 00165 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { 00166 const ValueDecl *VD = DRE->getDecl(); 00167 if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD)) 00168 return true; 00169 } 00170 return false; 00171 } 00172 00173 const MacOSKeychainAPIChecker::ADFunctionInfo 00174 MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = { 00175 {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0 00176 {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1 00177 {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2 00178 {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3 00179 {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4 00180 {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5 00181 {"free", 0, InvalidIdx, ErrorAPI}, // 6 00182 {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7 00183 }; 00184 00185 unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, 00186 bool IsAllocator) { 00187 for (unsigned I = 0; I < FunctionsToTrackSize; ++I) { 00188 ADFunctionInfo FI = FunctionsToTrack[I]; 00189 if (FI.Name != Name) 00190 continue; 00191 // Make sure the function is of the right type (allocator vs deallocator). 00192 if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx)) 00193 return InvalidIdx; 00194 if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx)) 00195 return InvalidIdx; 00196 00197 return I; 00198 } 00199 // The function is not tracked. 00200 return InvalidIdx; 00201 } 00202 00203 static bool isBadDeallocationArgument(const MemRegion *Arg) { 00204 if (!Arg) 00205 return false; 00206 if (isa<AllocaRegion>(Arg) || 00207 isa<BlockDataRegion>(Arg) || 00208 isa<TypedRegion>(Arg)) { 00209 return true; 00210 } 00211 return false; 00212 } 00213 00214 /// Given the address expression, retrieve the value it's pointing to. Assume 00215 /// that value is itself an address, and return the corresponding symbol. 00216 static SymbolRef getAsPointeeSymbol(const Expr *Expr, 00217 CheckerContext &C) { 00218 ProgramStateRef State = C.getState(); 00219 SVal ArgV = State->getSVal(Expr, C.getLocationContext()); 00220 00221 if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) { 00222 StoreManager& SM = C.getStoreManager(); 00223 SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol(); 00224 if (sym) 00225 return sym; 00226 } 00227 return nullptr; 00228 } 00229 00230 // When checking for error code, we need to consider the following cases: 00231 // 1) noErr / [0] 00232 // 2) someErr / [1, inf] 00233 // 3) unknown 00234 // If noError, returns true iff (1). 00235 // If !noError, returns true iff (2). 00236 bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym, 00237 ProgramStateRef State, 00238 SValBuilder &Builder, 00239 bool noError) const { 00240 DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr, 00241 Builder.getSymbolManager().getType(RetSym)); 00242 DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal, 00243 nonloc::SymbolVal(RetSym)); 00244 ProgramStateRef ErrState = State->assume(NoErr, noError); 00245 if (ErrState == State) { 00246 return true; 00247 } 00248 00249 return false; 00250 } 00251 00252 // Report deallocator mismatch. Remove the region from tracking - reporting a 00253 // missing free error after this one is redundant. 00254 void MacOSKeychainAPIChecker:: 00255 generateDeallocatorMismatchReport(const AllocationPair &AP, 00256 const Expr *ArgExpr, 00257 CheckerContext &C) const { 00258 ProgramStateRef State = C.getState(); 00259 State = State->remove<AllocatedData>(AP.first); 00260 ExplodedNode *N = C.addTransition(State); 00261 00262 if (!N) 00263 return; 00264 initBugType(); 00265 SmallString<80> sbuf; 00266 llvm::raw_svector_ostream os(sbuf); 00267 unsigned int PDeallocIdx = 00268 FunctionsToTrack[AP.second->AllocatorIdx].DeallocatorIdx; 00269 00270 os << "Deallocator doesn't match the allocator: '" 00271 << FunctionsToTrack[PDeallocIdx].Name << "' should be used."; 00272 BugReport *Report = new BugReport(*BT, os.str(), N); 00273 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first)); 00274 Report->addRange(ArgExpr->getSourceRange()); 00275 markInteresting(Report, AP); 00276 C.emitReport(Report); 00277 } 00278 00279 void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, 00280 CheckerContext &C) const { 00281 unsigned idx = InvalidIdx; 00282 ProgramStateRef State = C.getState(); 00283 00284 const FunctionDecl *FD = C.getCalleeDecl(CE); 00285 if (!FD || FD->getKind() != Decl::Function) 00286 return; 00287 00288 StringRef funName = C.getCalleeName(FD); 00289 if (funName.empty()) 00290 return; 00291 00292 // If it is a call to an allocator function, it could be a double allocation. 00293 idx = getTrackedFunctionIndex(funName, true); 00294 if (idx != InvalidIdx) { 00295 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 00296 if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) 00297 if (const AllocationState *AS = State->get<AllocatedData>(V)) { 00298 if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) { 00299 // Remove the value from the state. The new symbol will be added for 00300 // tracking when the second allocator is processed in checkPostStmt(). 00301 State = State->remove<AllocatedData>(V); 00302 ExplodedNode *N = C.addTransition(State); 00303 if (!N) 00304 return; 00305 initBugType(); 00306 SmallString<128> sbuf; 00307 llvm::raw_svector_ostream os(sbuf); 00308 unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 00309 os << "Allocated data should be released before another call to " 00310 << "the allocator: missing a call to '" 00311 << FunctionsToTrack[DIdx].Name 00312 << "'."; 00313 BugReport *Report = new BugReport(*BT, os.str(), N); 00314 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V)); 00315 Report->addRange(ArgExpr->getSourceRange()); 00316 Report->markInteresting(AS->Region); 00317 C.emitReport(Report); 00318 } 00319 } 00320 return; 00321 } 00322 00323 // Is it a call to one of deallocator functions? 00324 idx = getTrackedFunctionIndex(funName, false); 00325 if (idx == InvalidIdx) 00326 return; 00327 00328 // Check the argument to the deallocator. 00329 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 00330 SVal ArgSVal = State->getSVal(ArgExpr, C.getLocationContext()); 00331 00332 // Undef is reported by another checker. 00333 if (ArgSVal.isUndef()) 00334 return; 00335 00336 SymbolRef ArgSM = ArgSVal.getAsLocSymbol(); 00337 00338 // If the argument is coming from the heap, globals, or unknown, do not 00339 // report it. 00340 bool RegionArgIsBad = false; 00341 if (!ArgSM) { 00342 if (!isBadDeallocationArgument(ArgSVal.getAsRegion())) 00343 return; 00344 RegionArgIsBad = true; 00345 } 00346 00347 // Is the argument to the call being tracked? 00348 const AllocationState *AS = State->get<AllocatedData>(ArgSM); 00349 if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) { 00350 return; 00351 } 00352 // If trying to free data which has not been allocated yet, report as a bug. 00353 // TODO: We might want a more precise diagnostic for double free 00354 // (that would involve tracking all the freed symbols in the checker state). 00355 if (!AS || RegionArgIsBad) { 00356 // It is possible that this is a false positive - the argument might 00357 // have entered as an enclosing function parameter. 00358 if (isEnclosingFunctionParam(ArgExpr)) 00359 return; 00360 00361 ExplodedNode *N = C.addTransition(State); 00362 if (!N) 00363 return; 00364 initBugType(); 00365 BugReport *Report = new BugReport(*BT, 00366 "Trying to free data which has not been allocated.", N); 00367 Report->addRange(ArgExpr->getSourceRange()); 00368 if (AS) 00369 Report->markInteresting(AS->Region); 00370 C.emitReport(Report); 00371 return; 00372 } 00373 00374 // Process functions which might deallocate. 00375 if (FunctionsToTrack[idx].Kind == PossibleAPI) { 00376 00377 if (funName == "CFStringCreateWithBytesNoCopy") { 00378 const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts(); 00379 // NULL ~ default deallocator, so warn. 00380 if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(), 00381 Expr::NPC_ValueDependentIsNotNull)) { 00382 const AllocationPair AP = std::make_pair(ArgSM, AS); 00383 generateDeallocatorMismatchReport(AP, ArgExpr, C); 00384 return; 00385 } 00386 // One of the default allocators, so warn. 00387 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) { 00388 StringRef DeallocatorName = DE->getFoundDecl()->getName(); 00389 if (DeallocatorName == "kCFAllocatorDefault" || 00390 DeallocatorName == "kCFAllocatorSystemDefault" || 00391 DeallocatorName == "kCFAllocatorMalloc") { 00392 const AllocationPair AP = std::make_pair(ArgSM, AS); 00393 generateDeallocatorMismatchReport(AP, ArgExpr, C); 00394 return; 00395 } 00396 // If kCFAllocatorNull, which does not deallocate, we still have to 00397 // find the deallocator. 00398 if (DE->getFoundDecl()->getName() == "kCFAllocatorNull") 00399 return; 00400 } 00401 // In all other cases, assume the user supplied a correct deallocator 00402 // that will free memory so stop tracking. 00403 State = State->remove<AllocatedData>(ArgSM); 00404 C.addTransition(State); 00405 return; 00406 } 00407 00408 llvm_unreachable("We know of no other possible APIs."); 00409 } 00410 00411 // The call is deallocating a value we previously allocated, so remove it 00412 // from the next state. 00413 State = State->remove<AllocatedData>(ArgSM); 00414 00415 // Check if the proper deallocator is used. 00416 unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 00417 if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) { 00418 const AllocationPair AP = std::make_pair(ArgSM, AS); 00419 generateDeallocatorMismatchReport(AP, ArgExpr, C); 00420 return; 00421 } 00422 00423 // If the buffer can be null and the return status can be an error, 00424 // report a bad call to free. 00425 if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) && 00426 !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) { 00427 ExplodedNode *N = C.addTransition(State); 00428 if (!N) 00429 return; 00430 initBugType(); 00431 BugReport *Report = new BugReport(*BT, 00432 "Only call free if a valid (non-NULL) buffer was returned.", N); 00433 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(ArgSM)); 00434 Report->addRange(ArgExpr->getSourceRange()); 00435 Report->markInteresting(AS->Region); 00436 C.emitReport(Report); 00437 return; 00438 } 00439 00440 C.addTransition(State); 00441 } 00442 00443 void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, 00444 CheckerContext &C) const { 00445 ProgramStateRef State = C.getState(); 00446 const FunctionDecl *FD = C.getCalleeDecl(CE); 00447 if (!FD || FD->getKind() != Decl::Function) 00448 return; 00449 00450 StringRef funName = C.getCalleeName(FD); 00451 00452 // If a value has been allocated, add it to the set for tracking. 00453 unsigned idx = getTrackedFunctionIndex(funName, true); 00454 if (idx == InvalidIdx) 00455 return; 00456 00457 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 00458 // If the argument entered as an enclosing function parameter, skip it to 00459 // avoid false positives. 00460 if (isEnclosingFunctionParam(ArgExpr) && 00461 C.getLocationContext()->getParent() == nullptr) 00462 return; 00463 00464 if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { 00465 // If the argument points to something that's not a symbolic region, it 00466 // can be: 00467 // - unknown (cannot reason about it) 00468 // - undefined (already reported by other checker) 00469 // - constant (null - should not be tracked, 00470 // other constant will generate a compiler warning) 00471 // - goto (should be reported by other checker) 00472 00473 // The call return value symbol should stay alive for as long as the 00474 // allocated value symbol, since our diagnostics depend on the value 00475 // returned by the call. Ex: Data should only be freed if noErr was 00476 // returned during allocation.) 00477 SymbolRef RetStatusSymbol = 00478 State->getSVal(CE, C.getLocationContext()).getAsSymbol(); 00479 C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); 00480 00481 // Track the allocated value in the checker state. 00482 State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, 00483 RetStatusSymbol)); 00484 assert(State); 00485 C.addTransition(State); 00486 } 00487 } 00488 00489 // TODO: This logic is the same as in Malloc checker. 00490 const ExplodedNode * 00491 MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N, 00492 SymbolRef Sym, 00493 CheckerContext &C) const { 00494 const LocationContext *LeakContext = N->getLocationContext(); 00495 // Walk the ExplodedGraph backwards and find the first node that referred to 00496 // the tracked symbol. 00497 const ExplodedNode *AllocNode = N; 00498 00499 while (N) { 00500 if (!N->getState()->get<AllocatedData>(Sym)) 00501 break; 00502 // Allocation node, is the last node in the current context in which the 00503 // symbol was tracked. 00504 if (N->getLocationContext() == LeakContext) 00505 AllocNode = N; 00506 N = N->pred_empty() ? nullptr : *(N->pred_begin()); 00507 } 00508 00509 return AllocNode; 00510 } 00511 00512 BugReport *MacOSKeychainAPIChecker:: 00513 generateAllocatedDataNotReleasedReport(const AllocationPair &AP, 00514 ExplodedNode *N, 00515 CheckerContext &C) const { 00516 const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx]; 00517 initBugType(); 00518 SmallString<70> sbuf; 00519 llvm::raw_svector_ostream os(sbuf); 00520 os << "Allocated data is not released: missing a call to '" 00521 << FunctionsToTrack[FI.DeallocatorIdx].Name << "'."; 00522 00523 // Most bug reports are cached at the location where they occurred. 00524 // With leaks, we want to unique them by the location where they were 00525 // allocated, and only report a single path. 00526 PathDiagnosticLocation LocUsedForUniqueing; 00527 const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C); 00528 const Stmt *AllocStmt = nullptr; 00529 ProgramPoint P = AllocNode->getLocation(); 00530 if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) 00531 AllocStmt = Exit->getCalleeContext()->getCallSite(); 00532 else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>()) 00533 AllocStmt = PS->getStmt(); 00534 00535 if (AllocStmt) 00536 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt, 00537 C.getSourceManager(), 00538 AllocNode->getLocationContext()); 00539 00540 BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing, 00541 AllocNode->getLocationContext()->getDecl()); 00542 00543 Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first)); 00544 markInteresting(Report, AP); 00545 return Report; 00546 } 00547 00548 void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, 00549 CheckerContext &C) const { 00550 ProgramStateRef State = C.getState(); 00551 AllocatedDataTy ASet = State->get<AllocatedData>(); 00552 if (ASet.isEmpty()) 00553 return; 00554 00555 bool Changed = false; 00556 AllocationPairVec Errors; 00557 for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { 00558 if (SR.isLive(I->first)) 00559 continue; 00560 00561 Changed = true; 00562 State = State->remove<AllocatedData>(I->first); 00563 // If the allocated symbol is null or if the allocation call might have 00564 // returned an error, do not report. 00565 ConstraintManager &CMgr = State->getConstraintManager(); 00566 ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey()); 00567 if (AllocFailed.isConstrainedTrue() || 00568 definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) 00569 continue; 00570 Errors.push_back(std::make_pair(I->first, &I->second)); 00571 } 00572 if (!Changed) { 00573 // Generate the new, cleaned up state. 00574 C.addTransition(State); 00575 return; 00576 } 00577 00578 static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak"); 00579 ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); 00580 00581 // Generate the error reports. 00582 for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); 00583 I != E; ++I) { 00584 C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); 00585 } 00586 00587 // Generate the new, cleaned up state. 00588 C.addTransition(State, N); 00589 } 00590 00591 00592 PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode( 00593 const ExplodedNode *N, 00594 const ExplodedNode *PrevN, 00595 BugReporterContext &BRC, 00596 BugReport &BR) { 00597 const AllocationState *AS = N->getState()->get<AllocatedData>(Sym); 00598 if (!AS) 00599 return nullptr; 00600 const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym); 00601 if (ASPrev) 00602 return nullptr; 00603 00604 // (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the 00605 // allocation site. 00606 const CallExpr *CE = 00607 cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt()); 00608 const FunctionDecl *funDecl = CE->getDirectCallee(); 00609 assert(funDecl && "We do not support indirect function calls as of now."); 00610 StringRef funName = funDecl->getName(); 00611 00612 // Get the expression of the corresponding argument. 00613 unsigned Idx = getTrackedFunctionIndex(funName, true); 00614 assert(Idx != InvalidIdx && "This should be a call to an allocator."); 00615 const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param); 00616 PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(), 00617 N->getLocationContext()); 00618 return new PathDiagnosticEventPiece(Pos, "Data is allocated here."); 00619 } 00620 00621 void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) { 00622 mgr.registerChecker<MacOSKeychainAPIChecker>(); 00623 }