MacOSKeychainAPIChecker.cpp revision e94cb98d39fcd2cca68ab1b0d71f9a16b5e934c1
1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//==--- MacOSKeychainAPIChecker.cpp ------------------------------*- C++ -*-==// 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The LLVM Compiler Infrastructure 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This file is distributed under the University of Illinois Open Source 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// License. See LICENSE.TXT for details. 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//===----------------------------------------------------------------------===// 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This checker flags misuses of KeyChainAPI. In particular, the password data 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// allocated/returned by SecKeychainItemCopyContent, 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// to be freed using a call to SecKeychainItemFreeContent. 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//===----------------------------------------------------------------------===// 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "ClangSACheckers.h" 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/Checker.h" 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/CheckerManager.h" 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownusing namespace clang; 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownusing namespace ento; 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownnamespace { 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownclass MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>, 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check::PreStmt<ReturnStmt>, 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check::PostStmt<CallExpr>, 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check::EndPath, 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check::DeadSymbols> { 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mutable llvm::OwningPtr<BugType> BT; 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownpublic: 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// AllocationState is a part of the checker specific state together with the 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// MemRegion corresponding to the allocated data. 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct AllocationState { 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *Address; 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// The index of the allocator function. 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int AllocatorIdx; 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef RetValue; 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) : 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Address(E), 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown AllocatorIdx(Idx), 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RetValue(R) {} 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool operator==(const AllocationState &X) const { 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return Address == X.Address; 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Profile(llvm::FoldingSetNodeID &ID) const { 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ID.AddPointer(Address); 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ID.AddInteger(AllocatorIdx); 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void checkPreStmt(const CallExpr *S, CheckerContext &C) const; 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void checkPostStmt(const CallExpr *S, CheckerContext &C) const; 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownprivate: 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef std::pair<SymbolRef, const AllocationState&> AllocationPair; 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec; 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown enum APIKind { 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// Denotes functions tracked by this checker. 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ValidAPI = 0, 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// The functions commonly/mistakenly used in place of the given API. 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ErrorAPI = 1, 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// The functions which may allocate the data. These are tracked to reduce 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// the false alarm rate. 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown PossibleAPI = 2 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// Stores the information about the allocator and deallocator functions - 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// these are the functions the checker is tracking. 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct ADFunctionInfo { 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const char* Name; 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int Param; 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int DeallocatorIdx; 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown APIKind Kind; 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static const unsigned InvalidIdx = 100000; 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static const unsigned FunctionsToTrackSize = 8; 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static const ADFunctionInfo FunctionsToTrack[FunctionsToTrackSize]; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// The value, which represents no error return value for allocator functions. 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static const unsigned NoErr = 0; 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// Given the function name, returns the index of the allocator/deallocator 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// function. 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator); 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown inline void initBugType() const { 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!BT) 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API")); 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void generateDeallocatorMismatchReport(const AllocationState &AS, 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *ArgExpr, 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C, 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef ArgSM) const; 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP, 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ExplodedNode *N) const; 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// Check if RetSym evaluates to an error value in the current state. 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool definitelyReturnedError(SymbolRef RetSym, 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State, 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SValBuilder &Builder, 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool noError = false) const; 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// Check if RetSym evaluates to a NoErr value in the current state. 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool definitelyDidnotReturnError(SymbolRef RetSym, 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State, 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SValBuilder &Builder) const { 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return definitelyReturnedError(RetSym, State, Builder, true); 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// The bug visitor which allows us to print extra diagnostics along the 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// BugReport path. For example, showing the allocation site of the leaked 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /// region. 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown class SecKeychainBugVisitor : public BugReporterVisitor { 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown protected: 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The allocated region symbol tracked by the main analysis. 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef Sym; 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown public: 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SecKeychainBugVisitor(SymbolRef S) : Sym(S) {} 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown virtual ~SecKeychainBugVisitor() {} 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void Profile(llvm::FoldingSetNodeID &ID) const { 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static int X = 0; 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ID.AddPointer(&X); 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ID.AddPointer(Sym); 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ExplodedNode *PrevN, 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReporterContext &BRC, 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport &BR); 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// ProgramState traits to store the currently allocated (and not yet freed) 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// symbols. This is a map from the allocated content symbol to the 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// corresponding AllocationState. 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef llvm::ImmutableMap<SymbolRef, 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy; 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownnamespace { struct AllocatedData {}; } 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownnamespace clang { namespace ento { 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntemplate<> struct ProgramStateTrait<AllocatedData> 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : public ProgramStatePartialTrait<AllocatedSetTy > { 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown static void *GDMIndex() { static int index = 0; return &index; } 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}} 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic bool isEnclosingFunctionParam(const Expr *E) { 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown E = E->IgnoreParenCasts(); 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ValueDecl *VD = DRE->getDecl(); 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD)) 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return true; 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return false; 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst MacOSKeychainAPIChecker::ADFunctionInfo 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MacOSKeychainAPIChecker::FunctionsToTrack[FunctionsToTrackSize] = { 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainItemCopyContent", 4, 3, ValidAPI}, // 0 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainFindGenericPassword", 6, 3, ValidAPI}, // 1 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainFindInternetPassword", 13, 3, ValidAPI}, // 2 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainItemFreeContent", 1, InvalidIdx, ValidAPI}, // 3 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainItemCopyAttributesAndData", 5, 5, ValidAPI}, // 4 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"SecKeychainItemFreeAttributesAndData", 1, InvalidIdx, ValidAPI}, // 5 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"free", 0, InvalidIdx, ErrorAPI}, // 6 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown {"CFStringCreateWithBytesNoCopy", 1, InvalidIdx, PossibleAPI}, // 7 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownunsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool IsAllocator) { 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (unsigned I = 0; I < FunctionsToTrackSize; ++I) { 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ADFunctionInfo FI = FunctionsToTrack[I]; 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (FI.Name != Name) 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Make sure the function is of the right type (allocator vs deallocator). 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (IsAllocator && (FI.DeallocatorIdx == InvalidIdx)) 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return InvalidIdx; 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!IsAllocator && (FI.DeallocatorIdx != InvalidIdx)) 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return InvalidIdx; 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return I; 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The function is not tracked. 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return InvalidIdx; 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SymbolRef getSymbolForRegion(CheckerContext &C, 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const MemRegion *R) { 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!isa<SymbolicRegion>(R)) { 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Implicit casts (ex: void* -> char*) can turn Symbolic region into element 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // region, if that is the case, get the underlining region. 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown R = ER->getAsArrayOffset().getRegion(); 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return cast<SymbolicRegion>(R)->getSymbol(); 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic bool isBadDeallocationArgument(const MemRegion *Arg) { 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (isa<AllocaRegion>(Arg) || 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown isa<BlockDataRegion>(Arg) || 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown isa<TypedRegion>(Arg)) { 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return true; 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return false; 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// Given the address expression, retrieve the value it's pointing to. Assume 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/// that value is itself an address, and return the corresponding symbol. 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SymbolRef getAsPointeeSymbol(const Expr *Expr, 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C) { 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State = C.getState(); 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SVal ArgV = State->getSVal(Expr); 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) { 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown StoreManager& SM = C.getStoreManager(); 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion(); 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (V) 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return getSymbolForRegion(C, V); 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// When checking for error code, we need to consider the following cases: 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 1) noErr / [0] 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 2) someErr / [1, inf] 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 3) unknown 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If noError, returns true iff (1). 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If !noError, returns true iff (2). 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownbool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym, 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State, 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SValBuilder &Builder, 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool noError) const { 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr, 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Builder.getSymbolManager().getType(RetSym)); 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal, 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nonloc::SymbolVal(RetSym)); 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *ErrState = State->assume(NoErr, noError); 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ErrState == State) { 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return true; 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return false; 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Report deallocator mismatch. Remove the region from tracking - reporting a 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// missing free error after this one is redundant. 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MacOSKeychainAPIChecker:: 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown generateDeallocatorMismatchReport(const AllocationState &AS, 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *ArgExpr, 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C, 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef ArgSM) const { 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State = C.getState(); 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown State = State->remove<AllocatedData>(ArgSM); 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ExplodedNode *N = C.generateNode(State); 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!N) 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown initBugType(); 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown llvm::SmallString<80> sbuf; 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown llvm::raw_svector_ostream os(sbuf); 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int PDeallocIdx = FunctionsToTrack[AS.AllocatorIdx].DeallocatorIdx; 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown os << "Deallocator doesn't match the allocator: '" 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown << FunctionsToTrack[PDeallocIdx].Name << "' should be used."; 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport *Report = new BugReport(*BT, os.str(), N); 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Report->addRange(ArgExpr->getSourceRange()); 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.EmitReport(Report); 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C) const { 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State = C.getState(); 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *Callee = CE->getCallee(); 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SVal L = State->getSVal(Callee); 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned idx = InvalidIdx; 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const FunctionDecl *funDecl = L.getAsFunctionDecl(); 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!funDecl) 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown IdentifierInfo *funI = funDecl->getIdentifier(); 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!funI) 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown StringRef funName = funI->getName(); 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If it is a call to an allocator function, it could be a double allocation. 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown idx = getTrackedFunctionIndex(funName, true); 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (idx != InvalidIdx) { 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (const AllocationState *AS = State->get<AllocatedData>(V)) { 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!definitelyReturnedError(AS->RetValue, State, C.getSValBuilder())) { 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Remove the value from the state. The new symbol will be added for 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // tracking when the second allocator is processed in checkPostStmt(). 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown State = State->remove<AllocatedData>(V); 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ExplodedNode *N = C.generateNode(State); 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!N) 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown initBugType(); 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown llvm::SmallString<128> sbuf; 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown llvm::raw_svector_ostream os(sbuf); 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown os << "Allocated data should be released before another call to " 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown << "the allocator: missing a call to '" 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown << FunctionsToTrack[DIdx].Name 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown << "'."; 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport *Report = new BugReport(*BT, os.str(), N); 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Report->addRange(ArgExpr->getSourceRange()); 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.EmitReport(Report); 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Is it a call to one of deallocator functions? 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown idx = getTrackedFunctionIndex(funName, false); 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (idx == InvalidIdx) 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Check the argument to the deallocator. 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SVal ArgSVal = State->getSVal(ArgExpr); 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Undef is reported by another checker. 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ArgSVal.isUndef()) 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const MemRegion *Arg = ArgSVal.getAsRegion(); 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!Arg) 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef ArgSM = getSymbolForRegion(C, Arg); 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bool RegionArgIsBad = ArgSM ? false : isBadDeallocationArgument(Arg); 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If the argument is coming from the heap, globals, or unknown, do not 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // report it. 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ArgSM && !RegionArgIsBad) 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Is the argument to the call being tracked? 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const AllocationState *AS = State->get<AllocatedData>(ArgSM); 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) { 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If trying to free data which has not been allocated yet, report as a bug. 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // TODO: We might want a more precise diagnostic for double free 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // (that would involve tracking all the freed symbols in the checker state). 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!AS || RegionArgIsBad) { 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // It is possible that this is a false positive - the argument might 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // have entered as an enclosing function parameter. 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (isEnclosingFunctionParam(ArgExpr)) 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ExplodedNode *N = C.generateNode(State); 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!N) 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown initBugType(); 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport *Report = new BugReport(*BT, 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Trying to free data which has not been allocated.", N); 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Report->addRange(ArgExpr->getSourceRange()); 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.EmitReport(Report); 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Process functions which might deallocate. 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (FunctionsToTrack[idx].Kind == PossibleAPI) { 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (funName == "CFStringCreateWithBytesNoCopy") { 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *DeallocatorExpr = CE->getArg(5)->IgnoreParenCasts(); 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // NULL ~ default deallocator, so warn. 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DeallocatorExpr->isNullPointerConstant(C.getASTContext(), 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Expr::NPC_ValueDependentIsNotNull)) { 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown generateDeallocatorMismatchReport(*AS, ArgExpr, C, ArgSM); 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // One of the default allocators, so warn. 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(DeallocatorExpr)) { 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown StringRef DeallocatorName = DE->getFoundDecl()->getName(); 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DeallocatorName == "kCFAllocatorDefault" || 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DeallocatorName == "kCFAllocatorSystemDefault" || 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DeallocatorName == "kCFAllocatorMalloc") { 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown generateDeallocatorMismatchReport(*AS, ArgExpr, C, ArgSM); 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If kCFAllocatorNull, which does not deallocate, we still have to 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // find the deallocator. Otherwise, assume that the user had written a 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // custom deallocator which does the right thing. 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DE->getFoundDecl()->getName() != "kCFAllocatorNull") { 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown State = State->remove<AllocatedData>(ArgSM); 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.addTransition(State); 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 409436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov } 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The call is deallocating a value we previously allocated, so remove it 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // from the next state. 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown State = State->remove<AllocatedData>(ArgSM); 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Check if the proper deallocator is used. 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int PDeallocIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx; 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (PDeallocIdx != idx || (FunctionsToTrack[idx].Kind == ErrorAPI)) { 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown generateDeallocatorMismatchReport(*AS, ArgExpr, C, ArgSM); 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If the return status is undefined or is error, report a bad call to free. 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!definitelyDidnotReturnError(AS->RetValue, State, C.getSValBuilder())) { 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ExplodedNode *N = C.generateNode(State); 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!N) 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown initBugType(); 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown BugReport *Report = new BugReport(*BT, 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Call to free data when error was returned during allocation.", N); 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Report->addRange(ArgExpr->getSourceRange()); 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.EmitReport(Report); 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.addTransition(State); 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C) const { 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *State = C.getState(); 441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *Callee = CE->getCallee(); 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SVal L = State->getSVal(Callee); 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const FunctionDecl *funDecl = L.getAsFunctionDecl(); 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!funDecl) 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown IdentifierInfo *funI = funDecl->getIdentifier(); 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!funI) 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown StringRef funName = funI->getName(); 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If a value has been allocated, add it to the set for tracking. 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned idx = getTrackedFunctionIndex(funName, true); 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (idx == InvalidIdx) 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If the argument entered as an enclosing function parameter, skip it to 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // avoid false positives. 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (isEnclosingFunctionParam(ArgExpr)) 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) { 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If the argument points to something that's not a symbolic region, it 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // can be: 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - unknown (cannot reason about it) 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - undefined (already reported by other checker) 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - constant (null - should not be tracked, 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // other constant will generate a compiler warning) 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - goto (should be reported by other checker) 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The call return value symbol should stay alive for as long as the 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // allocated value symbol, since our diagnostics depend on the value 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // returned by the call. Ex: Data should only be freed if noErr was 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // returned during allocation.) 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol(); 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.getSymbolManager().addSymbolDependency(V, RetStatusSymbol); 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Track the allocated value in the checker state. 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown State = State->set<AllocatedData>(V, AllocationState(ArgExpr, idx, 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RetStatusSymbol)); 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(State); 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown C.addTransition(State); 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S, 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown CheckerContext &C) const { 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Expr *retExpr = S->getRetValue(); 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!retExpr) 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Check if the value is escaping through the return. 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ProgramState *state = C.getState(); 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const MemRegion *V = state->getSVal(retExpr).getAsRegion(); 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!V) 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 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