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