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