Coverage Report

Created: 2020-09-19 12:23

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
Line
Count
Source (jump to first uncovered line)
1
// RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- C++ -*--//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file defines diagnostics for RetainCountChecker, which implements
10
//  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "RetainCountDiagnostics.h"
15
#include "RetainCountChecker.h"
16
17
using namespace clang;
18
using namespace ento;
19
using namespace retaincountchecker;
20
21
960
StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugKind BT) {
22
960
  switch (BT) {
23
120
  case UseAfterRelease:
24
120
    return "Use-after-release";
25
120
  case ReleaseNotOwned:
26
120
    return "Bad release";
27
120
  case DeallocNotOwned:
28
120
    return "-dealloc sent to non-exclusively owned object";
29
120
  case FreeNotOwned:
30
120
    return "freeing non-exclusively owned object";
31
120
  case OverAutorelease:
32
120
    return "Object autoreleased too many times";
33
120
  case ReturnNotOwnedForOwned:
34
120
    return "Method should return an owned object";
35
120
  case LeakWithinFunction:
36
120
    return "Leak";
37
120
  case LeakAtReturn:
38
120
    return "Leak of returned object";
39
0
  }
40
0
  llvm_unreachable("Unknown RefCountBugKind");
41
0
}
42
43
592
StringRef RefCountBug::getDescription() const {
44
592
  switch (BT) {
45
59
  case UseAfterRelease:
46
59
    return "Reference-counted object is used after it is released";
47
51
  case ReleaseNotOwned:
48
51
    return "Incorrect decrement of the reference count of an object that is "
49
51
           "not owned at this point by the caller";
50
0
  case DeallocNotOwned:
51
0
    return "-dealloc sent to object that may be referenced elsewhere";
52
1
  case FreeNotOwned:
53
1
    return  "'free' called on an object that may be referenced elsewhere";
54
32
  case OverAutorelease:
55
32
    return "Object autoreleased too many times";
56
25
  case ReturnNotOwnedForOwned:
57
25
    return "Object with a +0 retain count returned to caller where a +1 "
58
25
           "(owning) retain count is expected";
59
424
  case LeakWithinFunction:
60
424
  case LeakAtReturn:
61
424
    return "";
62
0
  }
63
0
  llvm_unreachable("Unknown RefCountBugKind");
64
0
}
65
66
RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT)
67
    : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount,
68
              /*SuppressOnSink=*/BT == LeakWithinFunction ||
69
                  BT == LeakAtReturn),
70
960
      BT(BT) {}
71
72
20
static bool isNumericLiteralExpression(const Expr *E) {
73
  // FIXME: This set of cases was copied from SemaExprObjC.
74
20
  return isa<IntegerLiteral>(E) ||
75
12
         isa<CharacterLiteral>(E) ||
76
12
         isa<FloatingLiteral>(E) ||
77
12
         isa<ObjCBoolLiteralExpr>(E) ||
78
12
         isa<CXXBoolLiteralExpr>(E);
79
20
}
80
81
/// If type represents a pointer to CXXRecordDecl,
82
/// and is not a typedef, return the decl name.
83
/// Otherwise, return the serialization of type.
84
283
static std::string getPrettyTypeName(QualType QT) {
85
283
  QualType PT = QT->getPointeeType();
86
283
  if (!PT.isNull() && !QT->getAs<TypedefType>())
87
133
    if (const auto *RD = PT->getAsCXXRecordDecl())
88
45
      return std::string(RD->getName());
89
238
  return QT.getAsString();
90
238
}
91
92
/// Write information about the type state change to {@code os},
93
/// return whether the note should be generated.
94
static bool shouldGenerateNote(llvm::raw_string_ostream &os,
95
                               const RefVal *PrevT,
96
                               const RefVal &CurrV,
97
9.75k
                               bool DeallocSent) {
98
  // Get the previous type state.
99
9.75k
  RefVal PrevV = *PrevT;
100
9.75k
101
  // Specially handle -dealloc.
102
9.75k
  if (DeallocSent) {
103
    // Determine if the object's reference count was pushed to zero.
104
5
    assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
105
    // We may not have transitioned to 'release' if we hit an error.
106
    // This case is handled elsewhere.
107
5
    if (CurrV.getKind() == RefVal::Released) {
108
5
      assert(CurrV.getCombinedCounts() == 0);
109
5
      os << "Object released by directly sending the '-dealloc' message";
110
5
      return true;
111
5
    }
112
9.74k
  }
113
9.74k
114
  // Determine if the typestate has changed.
115
9.74k
  if (!PrevV.hasSameState(CurrV))
116
288
    switch (CurrV.getKind()) {
117
237
    case RefVal::Owned:
118
237
    case RefVal::NotOwned:
119
237
      if (PrevV.getCount() == CurrV.getCount()) {
120
        // Did an autorelease message get sent?
121
96
        if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
122
22
          return false;
123
74
124
74
        assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
125
74
        os << "Object autoreleased";
126
74
        return true;
127
74
      }
128
141
129
141
      if (PrevV.getCount() > CurrV.getCount())
130
31
        os << "Reference count decremented.";
131
110
      else
132
110
        os << "Reference count incremented.";
133
141
134
141
      if (unsigned Count = CurrV.getCount())
135
133
        os << " The object now has a +" << Count << " retain count.";
136
141
137
141
      return true;
138
141
139
51
    case RefVal::Released:
140
51
      if (CurrV.getIvarAccessHistory() ==
141
51
              RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
142
0
          CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
143
0
        os << "Strong instance variable relinquished. ";
144
0
      }
145
51
      os << "Object released.";
146
51
      return true;
147
141
148
0
    case RefVal::ReturnedOwned:
149
      // Autoreleases can be applied after marking a node ReturnedOwned.
150
0
      if (CurrV.getAutoreleaseCount())
151
0
        return false;
152
0
153
0
      os << "Object returned to caller as an owning reference (single "
154
0
            "retain count transferred to caller)";
155
0
      return true;
156
0
157
0
    case RefVal::ReturnedNotOwned:
158
0
      os << "Object returned to caller with a +0 retain count";
159
0
      return true;
160
0
161
0
    default:
162
0
      return false;
163
9.45k
    }
164
9.45k
  return true;
165
9.45k
}
166
167
/// Finds argument index of the out paramter in the call {@code S}
168
/// corresponding to the symbol {@code Sym}.
169
/// If none found, returns None.
170
static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
171
                                             const LocationContext *LCtx,
172
                                             SymbolRef &Sym,
173
490
                                             Optional<CallEventRef<>> CE) {
174
490
  if (!CE)
175
0
    return None;
176
490
177
1.00k
  
for (unsigned Idx = 0; 490
Idx < (*CE)->getNumArgs();
Idx++513
)
178
530
    if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
179
238
      if (const auto *TR = dyn_cast<TypedValueRegion>(MR))
180
101
        if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym)
181
17
          return Idx;
182
490
183
473
  return None;
184
490
}
185
186
24
static Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
187
24
  if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
188
3
    if (ME->getMemberDecl()->getNameAsString() != "alloc")
189
2
      return None;
190
1
    const Expr *This = ME->getBase()->IgnoreParenImpCasts();
191
1
    if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
192
1
      const ValueDecl *VD = DRE->getDecl();
193
1
      if (VD->getNameAsString() != "metaClass")
194
0
        return None;
195
1
196
1
      if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
197
1
        return RD->getNameAsString();
198
21
199
21
    }
200
1
  }
201
21
  return None;
202
21
}
203
204
33
static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
205
33
  if (const auto *CE = dyn_cast<CallExpr>(S))
206
24
    if (auto Out = findMetaClassAlloc(CE->getCallee()))
207
1
      return *Out;
208
32
  return getPrettyTypeName(QT);
209
32
}
210
211
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
212
                                           const LocationContext *LCtx,
213
                                           const RefVal &CurrV, SymbolRef &Sym,
214
                                           const Stmt *S,
215
490
                                           llvm::raw_string_ostream &os) {
216
490
  CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
217
490
  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
218
    // Get the name of the callee (if it is available)
219
    // from the tracked SVal.
220
254
    SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
221
254
    const FunctionDecl *FD = X.getAsFunctionDecl();
222
254
223
    // If failed, try to get it from AST.
224
254
    if (!FD)
225
3
      FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
226
254
227
254
    if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
228
13
      os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
229
241
    } else if (FD) {
230
241
      os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
231
0
    } else {
232
0
      os << "function call";
233
0
    }
234
236
  } else if (isa<CXXNewExpr>(S)) {
235
9
    os << "Operator 'new'";
236
227
  } else {
237
227
    assert(isa<ObjCMessageExpr>(S));
238
227
    CallEventRef<ObjCMethodCall> Call =
239
227
        Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
240
227
241
227
    switch (Call->getMessageKind()) {
242
215
    case OCM_Message:
243
215
      os << "Method";
244
215
      break;
245
6
    case OCM_PropertyAccess:
246
6
      os << "Property";
247
6
      break;
248
6
    case OCM_Subscript:
249
6
      os << "Subscript";
250
6
      break;
251
490
    }
252
490
  }
253
490
254
490
  Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
255
490
  auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
256
490
257
  // If index is not found, we assume that the symbol was returned.
258
490
  if (!Idx) {
259
473
    os << " returns ";
260
17
  } else {
261
17
    os << " writes ";
262
17
  }
263
490
264
490
  if (CurrV.getObjKind() == ObjKind::CF) {
265
237
    os << "a Core Foundation object of type '"
266
237
       << Sym->getType().getAsString() << "' with a ";
267
253
  } else if (CurrV.getObjKind() == ObjKind::OS) {
268
33
    os << "an OSObject of type '" << findAllocatedObjectName(S, Sym->getType())
269
33
       << "' with a ";
270
220
  } else if (CurrV.getObjKind() == ObjKind::Generalized) {
271
3
    os << "an object of type '" << Sym->getType().getAsString()
272
3
       << "' with a ";
273
217
  } else {
274
217
    assert(CurrV.getObjKind() == ObjKind::ObjC);
275
217
    QualType T = Sym->getType();
276
217
    if (!isa<ObjCObjectPointerType>(T)) {
277
63
      os << "an Objective-C object with a ";
278
154
    } else {
279
154
      const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
280
154
      os << "an instance of " << PT->getPointeeType().getAsString()
281
154
         << " with a ";
282
154
    }
283
217
  }
284
490
285
490
  if (CurrV.isOwned()) {
286
411
    os << "+1 retain count";
287
79
  } else {
288
79
    assert(CurrV.isNotOwned());
289
79
    os << "+0 retain count";
290
79
  }
291
490
292
490
  if (Idx) {
293
17
    os << " into an out parameter '";
294
17
    const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
295
17
    PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
296
17
                              /*Qualified=*/false);
297
17
    os << "'";
298
17
299
17
    QualType RT = (*CE)->getResultType();
300
17
    if (!RT.isNull() && !RT->isVoidType()) {
301
7
      SVal RV = (*CE)->getReturnValue();
302
7
      if (CurrSt->isNull(RV).isConstrainedTrue()) {
303
2
        os << " (assuming the call returns zero)";
304
5
      } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
305
5
        os << " (assuming the call returns non-zero)";
306
5
      }
307
7
308
7
    }
309
17
  }
310
490
}
311
312
namespace clang {
313
namespace ento {
314
namespace retaincountchecker {
315
316
class RefCountReportVisitor : public BugReporterVisitor {
317
protected:
318
  SymbolRef Sym;
319
320
public:
321
592
  RefCountReportVisitor(SymbolRef sym) : Sym(sym) {}
322
323
592
  void Profile(llvm::FoldingSetNodeID &ID) const override {
324
592
    static int x = 0;
325
592
    ID.AddPointer(&x);
326
592
    ID.AddPointer(Sym);
327
592
  }
328
329
  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
330
                                   BugReporterContext &BRC,
331
                                   PathSensitiveBugReport &BR) override;
332
333
  PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
334
                                    const ExplodedNode *N,
335
                                    PathSensitiveBugReport &BR) override;
336
};
337
338
class RefLeakReportVisitor : public RefCountReportVisitor {
339
public:
340
424
  RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
341
342
  PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
343
                                    const ExplodedNode *N,
344
                                    PathSensitiveBugReport &BR) override;
345
};
346
347
} // end namespace retaincountchecker
348
} // end namespace ento
349
} // end namespace clang
350
351
352
/// Find the first node with the parent stack frame.
353
110
static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
354
110
  const StackFrameContext *SC = Pred->getStackFrame();
355
110
  if (SC->inTopFrame())
356
0
    return nullptr;
357
110
  const StackFrameContext *PC = SC->getParent()->getStackFrame();
358
110
  if (!PC)
359
0
    return nullptr;
360
110
361
110
  const ExplodedNode *N = Pred;
362
2.26k
  while (N && N->getStackFrame() != PC) {
363
2.15k
    N = N->getFirstPred();
364
2.15k
  }
365
110
  return N;
366
110
}
367
368
369
/// Insert a diagnostic piece at function exit
370
/// if a function parameter is annotated as "os_consumed",
371
/// but it does not actually consume the reference.
372
static std::shared_ptr<PathDiagnosticEventPiece>
373
annotateConsumedSummaryMismatch(const ExplodedNode *N,
374
                                CallExitBegin &CallExitLoc,
375
                                const SourceManager &SM,
376
110
                                CallEventManager &CEMgr) {
377
110
378
110
  const ExplodedNode *CN = getCalleeNode(N);
379
110
  if (!CN)
380
0
    return nullptr;
381
110
382
110
  CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());
383
110
384
110
  std::string sbuf;
385
110
  llvm::raw_string_ostream os(sbuf);
386
110
  ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
387
163
  for (unsigned I=0; I < Call->getNumArgs() && 
I < Parameters.size()53
;
++I53
) {
388
53
    const ParmVarDecl *PVD = Parameters[I];
389
53
390
53
    if (!PVD->hasAttr<OSConsumedAttr>())
391
51
      continue;
392
2
393
2
    if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
394
2
      const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
395
2
      const RefVal *CountAtExit = getRefBinding(N->getState(), SR);
396
2
397
2
      if (!CountBeforeCall || !CountAtExit)
398
0
        continue;
399
2
400
2
      unsigned CountBefore = CountBeforeCall->getCount();
401
2
      unsigned CountAfter = CountAtExit->getCount();
402
2
403
2
      bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
404
2
      if (!AsExpected) {
405
2
        os << "Parameter '";
406
2
        PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
407
2
                                  /*Qualified=*/false);
408
2
        os << "' is marked as consuming, but the function did not consume "
409
2
           << "the reference\n";
410
2
      }
411
2
    }
412
2
  }
413
110
414
110
  if (os.str().empty())
415
108
    return nullptr;
416
2
417
2
  PathDiagnosticLocation L = PathDiagnosticLocation::create(CallExitLoc, SM);
418
2
  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
419
2
}
420
421
/// Annotate the parameter at the analysis entry point.
422
static std::shared_ptr<PathDiagnosticEventPiece>
423
annotateStartParameter(const ExplodedNode *N, SymbolRef Sym,
424
24.8k
                       const SourceManager &SM) {
425
24.8k
  auto PP = N->getLocationAs<BlockEdge>();
426
24.8k
  if (!PP)
427
24.1k
    return nullptr;
428
733
429
733
  const CFGBlock *Src = PP->getSrc();
430
733
  const RefVal *CurrT = getRefBinding(N->getState(), Sym);
431
733
432
733
  if (&Src->getParent()->getEntry() != Src || 
!CurrT163
||
433
80
      getRefBinding(N->getFirstPred()->getState(), Sym))
434
720
    return nullptr;
435
13
436
13
  const auto *VR = cast<VarRegion>(cast<SymbolRegionValue>(Sym)->getRegion());
437
13
  const auto *PVD = cast<ParmVarDecl>(VR->getDecl());
438
13
  PathDiagnosticLocation L = PathDiagnosticLocation(PVD, SM);
439
13
440
13
  std::string s;
441
13
  llvm::raw_string_ostream os(s);
442
13
  os << "Parameter '" << PVD->getDeclName() << "' starts at +";
443
13
  if (CurrT->getCount() == 1) {
444
5
    os << "1, as it is marked as consuming";
445
8
  } else {
446
8
    assert(CurrT->getCount() == 0);
447
8
    os << "0";
448
8
  }
449
13
  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
450
13
}
451
452
PathDiagnosticPieceRef
453
RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
454
24.8k
                                 PathSensitiveBugReport &BR) {
455
24.8k
456
24.8k
  const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
457
24.8k
458
24.8k
  bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned ||
459
24.8k
                       BT.getBugType() == RefCountBug::DeallocNotOwned;
460
24.8k
461
24.8k
  const SourceManager &SM = BRC.getSourceManager();
462
24.8k
  CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
463
24.8k
  if (auto CE = N->getLocationAs<CallExitBegin>())
464
110
    if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
465
2
      return PD;
466
24.8k
467
24.8k
  if (auto PD = annotateStartParameter(N, Sym, SM))
468
13
    return PD;
469
24.8k
470
  // FIXME: We will eventually need to handle non-statement-based events
471
  // (__attribute__((cleanup))).
472
24.8k
  if (!N->getLocation().getAs<StmtPoint>())
473
2.00k
    return nullptr;
474
22.8k
475
  // Check if the type state has changed.
476
22.8k
  const ExplodedNode *PrevNode = N->getFirstPred();
477
22.8k
  ProgramStateRef PrevSt = PrevNode->getState();
478
22.8k
  ProgramStateRef CurrSt = N->getState();
479
22.8k
  const LocationContext *LCtx = N->getLocationContext();
480
22.8k
481
22.8k
  const RefVal* CurrT = getRefBinding(CurrSt, Sym);
482
22.8k
  if (!CurrT)
483
12.5k
    return nullptr;
484
10.2k
485
10.2k
  const RefVal &CurrV = *CurrT;
486
10.2k
  const RefVal *PrevT = getRefBinding(PrevSt, Sym);
487
10.2k
488
  // Create a string buffer to constain all the useful things we want
489
  // to tell the user.
490
10.2k
  std::string sbuf;
491
10.2k
  llvm::raw_string_ostream os(sbuf);
492
10.2k
493
10.2k
  if (PrevT && 
IsFreeUnowned9.75k
&&
CurrV.isNotOwned()31
&&
PrevT->isOwned()9
) {
494
1
    os << "Object is now not exclusively owned";
495
1
    auto Pos = PathDiagnosticLocation::create(N->getLocation(), SM);
496
1
    return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
497
1
  }
498
10.2k
499
  // This is the allocation site since the previous node had no bindings
500
  // for this symbol.
501
10.2k
  if (!PrevT) {
502
526
    const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
503
526
504
526
    if (isa<ObjCIvarRefExpr>(S) &&
505
6
        isSynthesizedAccessor(LCtx->getStackFrame())) {
506
6
      S = LCtx->getStackFrame()->getCallSite();
507
6
    }
508
526
509
526
    if (isa<ObjCArrayLiteral>(S)) {
510
11
      os << "NSArray literal is an object with a +0 retain count";
511
515
    } else if (isa<ObjCDictionaryLiteral>(S)) {
512
5
      os << "NSDictionary literal is an object with a +0 retain count";
513
510
    } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
514
20
      if (isNumericLiteralExpression(BL->getSubExpr()))
515
8
        os << "NSNumber literal is an object with a +0 retain count";
516
12
      else {
517
12
        const ObjCInterfaceDecl *BoxClass = nullptr;
518
12
        if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
519
12
          BoxClass = Method->getClassInterface();
520
12
521
        // We should always be able to find the boxing class interface,
522
        // but consider this future-proofing.
523
12
        if (BoxClass) {
524
12
          os << *BoxClass << " b";
525
0
        } else {
526
0
          os << "B";
527
0
        }
528
12
529
12
        os << "oxed expression produces an object with a +0 retain count";
530
12
      }
531
490
    } else if (isa<ObjCIvarRefExpr>(S)) {
532
0
      os << "Object loaded from instance variable";
533
490
    } else {
534
490
      generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
535
490
    }
536
526
537
526
    PathDiagnosticLocation Pos(S, SM, N->getLocationContext());
538
526
    return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
539
526
  }
540
9.75k
541
  // Gather up the effects that were performed on the object at this
542
  // program point
543
9.75k
  bool DeallocSent = false;
544
9.75k
545
9.75k
  const ProgramPointTag *Tag = N->getLocation().getTag();
546
9.75k
547
9.75k
  if (Tag == &RetainCountChecker::getCastFailTag()) {
548
2
    os << "Assuming dynamic cast returns null due to type mismatch";
549
2
  }
550
9.75k
551
9.75k
  if (Tag == &RetainCountChecker::getDeallocSentTag()) {
552
    // We only have summaries attached to nodes after evaluating CallExpr and
553
    // ObjCMessageExprs.
554
5
    const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
555
5
556
5
    if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
557
      // Iterate through the parameter expressions and see if the symbol
558
      // was ever passed as an argument.
559
0
      unsigned i = 0;
560
0
561
0
      for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
562
0
563
        // Retrieve the value of the argument.  Is it the symbol
564
        // we are interested in?
565
0
        if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
566
0
          continue;
567
0
568
        // We have an argument.  Get the effect!
569
0
        DeallocSent = true;
570
0
      }
571
5
    } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
572
5
      if (const Expr *receiver = ME->getInstanceReceiver()) {
573
5
        if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
574
5
              .getAsLocSymbol() == Sym) {
575
          // The symbol we are tracking is the receiver.
576
5
          DeallocSent = true;
577
5
        }
578
5
      }
579
5
    }
580
5
  }
581
9.75k
582
9.75k
  if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent))
583
22
    return nullptr;
584
9.72k
585
9.72k
  if (os.str().empty())
586
9.45k
    return nullptr; // We have nothing to say!
587
273
588
273
  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
589
273
  PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
590
273
                                N->getLocationContext());
591
273
  auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
592
273
593
  // Add the range by scanning the children of the statement for any bindings
594
  // to Sym.
595
273
  for (const Stmt *Child : S->children())
596
380
    if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
597
380
      if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
598
258
        P->addRange(Exp->getSourceRange());
599
258
        break;
600
258
      }
601
273
602
273
  return std::move(P);
603
273
}
604
605
798
static Optional<std::string> describeRegion(const MemRegion *MR) {
606
798
  if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
607
547
    return std::string(VR->getDecl()->getName());
608
  // Once we support more storage locations for bindings,
609
  // this would need to be improved.
610
251
  return None;
611
251
}
612
613
namespace {
614
// Find the first node in the current function context that referred to the
615
// tracked symbol and the memory location that value was stored to. Note, the
616
// value is only reported if the allocation occurred in the same function as
617
// the leak. The function can also return a location context, which should be
618
// treated as interesting.
619
struct AllocationInfo {
620
  const ExplodedNode* N;
621
  const MemRegion *R;
622
  const LocationContext *InterestingMethodContext;
623
  AllocationInfo(const ExplodedNode *InN,
624
                 const MemRegion *InR,
625
                 const LocationContext *InInterestingMethodContext) :
626
798
    N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
627
};
628
} // end anonymous namespace
629
630
static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
631
798
                                        const ExplodedNode *N, SymbolRef Sym) {
632
798
  const ExplodedNode *AllocationNode = N;
633
798
  const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
634
798
  const MemRegion *FirstBinding = nullptr;
635
798
  const LocationContext *LeakContext = N->getLocationContext();
636
798
637
  // The location context of the init method called on the leaked object, if
638
  // available.
639
798
  const LocationContext *InitMethodContext = nullptr;
640
798
641
17.6k
  while (N) {
642
17.6k
    ProgramStateRef St = N->getState();
643
17.6k
    const LocationContext *NContext = N->getLocationContext();
644
17.6k
645
17.6k
    if (!getRefBinding(St, Sym))
646
798
      break;
647
16.8k
648
16.8k
    StoreManager::FindUniqueBinding FB(Sym);
649
16.8k
    StateMgr.iterBindings(St, FB);
650
16.8k
651
16.8k
    if (FB) {
652
9.15k
      const MemRegion *R = FB.getRegion();
653
      // Do not show local variables belonging to a function other than
654
      // where the error is reported.
655
9.15k
      if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
656
9.15k
        if (MR->getStackFrame() == LeakContext->getStackFrame())
657
8.06k
          FirstBinding = R;
658
9.15k
    }
659
16.8k
660
    // AllocationNode is the last node in which the symbol was tracked.
661
16.8k
    AllocationNode = N;
662
16.8k
663
    // AllocationNodeInCurrentContext, is the last node in the current or
664
    // parent context in which the symbol was tracked.
665
    //
666
    // Note that the allocation site might be in the parent context. For example,
667
    // the case where an allocation happens in a block that captures a reference
668
    // to it and that reference is overwritten/dropped by another call to
669
    // the block.
670
16.8k
    if (NContext == LeakContext || 
NContext->isParentOf(LeakContext)2.60k
)
671
14.4k
      AllocationNodeInCurrentOrParentContext = N;
672
16.8k
673
    // Find the last init that was called on the given symbol and store the
674
    // init method's location context.
675
16.8k
    if (!InitMethodContext)
676
16.7k
      if (auto CEP = N->getLocation().getAs<CallEnter>()) {
677
102
        const Stmt *CE = CEP->getCallExpr();
678
102
        if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
679
16
          const Stmt *RecExpr = ME->getInstanceReceiver();
680
16
          if (RecExpr) {
681
16
            SVal RecV = St->getSVal(RecExpr, NContext);
682
16
            if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
683
16
              InitMethodContext = CEP->getCalleeContext();
684
16
          }
685
16
        }
686
102
      }
687
16.8k
688
16.8k
    N = N->getFirstPred();
689
16.8k
  }
690
798
691
  // If we are reporting a leak of the object that was allocated with alloc,
692
  // mark its init method as interesting.
693
798
  const LocationContext *InterestingMethodContext = nullptr;
694
798
  if (InitMethodContext) {
695
16
    const ProgramPoint AllocPP = AllocationNode->getLocation();
696
16
    if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
697
16
      if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
698
16
        if (ME->getMethodFamily() == OMF_alloc)
699
16
          InterestingMethodContext = InitMethodContext;
700
16
  }
701
798
702
  // If allocation happened in a function different from the leak node context,
703
  // do not report the binding.
704
798
  assert(N && "Could not find allocation node");
705
798
706
798
  if (AllocationNodeInCurrentOrParentContext &&
707
798
      AllocationNodeInCurrentOrParentContext->getLocationContext() !=
708
798
      LeakContext)
709
4
    FirstBinding = nullptr;
710
798
711
798
  return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding,
712
798
                        InterestingMethodContext);
713
798
}
714
715
PathDiagnosticPieceRef
716
RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
717
                                  const ExplodedNode *EndN,
718
165
                                  PathSensitiveBugReport &BR) {
719
165
  BR.markInteresting(Sym);
720
165
  return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
721
165
}
722
723
PathDiagnosticPieceRef
724
RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
725
                                 const ExplodedNode *EndN,
726
374
                                 PathSensitiveBugReport &BR) {
727
374
728
  // Tell the BugReporterContext to report cases when the tracked symbol is
729
  // assigned to different variables, etc.
730
374
  BR.markInteresting(Sym);
731
374
732
  // We are reporting a leak.  Walk up the graph to get to the first node where
733
  // the symbol appeared, and also get the first VarDecl that tracked object
734
  // is stored to.
735
374
  AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
736
374
737
374
  const MemRegion* FirstBinding = AllocI.R;
738
374
  BR.markInteresting(AllocI.InterestingMethodContext);
739
374
740
374
  PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath();
741
374
742
374
  std::string sbuf;
743
374
  llvm::raw_string_ostream os(sbuf);
744
374
745
374
  os << "Object leaked: ";
746
374
747
374
  Optional<std::string> RegionDescription = describeRegion(FirstBinding);
748
374
  if (RegionDescription) {
749
249
    os << "object allocated and stored into '" << *RegionDescription << '\'';
750
125
  } else {
751
125
    os << "allocated object of type '" << getPrettyTypeName(Sym->getType())
752
125
       << "'";
753
125
  }
754
374
755
  // Get the retain count.
756
374
  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
757
374
  assert(RV);
758
374
759
374
  if (RV->getKind() == RefVal::ErrorLeakReturned) {
760
    // FIXME: Per comments in rdar://6320065, "create" only applies to CF
761
    // objects.  Only "copy", "alloc", "retain" and "new" transfer ownership
762
    // to the caller for NS objects.
763
53
    const Decl *D = &EndN->getCodeDecl();
764
53
765
32
    os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
766
21
                                  : " is returned from a function ");
767
53
768
53
    if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
769
1
      os << "that is annotated as CF_RETURNS_NOT_RETAINED";
770
52
    } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
771
3
      os << "that is annotated as NS_RETURNS_NOT_RETAINED";
772
49
    } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
773
0
      os << "that is annotated as OS_RETURNS_NOT_RETAINED";
774
49
    } else {
775
49
      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
776
29
        if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
777
1
          os << "managed by Automatic Reference Counting";
778
28
        } else {
779
28
          os << "whose name ('" << MD->getSelector().getAsString()
780
28
             << "') does not start with "
781
28
                "'copy', 'mutableCopy', 'alloc' or 'new'."
782
28
                "  This violates the naming convention rules"
783
28
                " given in the Memory Management Guide for Cocoa";
784
28
        }
785
20
      } else {
786
20
        const FunctionDecl *FD = cast<FunctionDecl>(D);
787
20
        ObjKind K = RV->getObjKind();
788
20
        if (K == ObjKind::ObjC || K == ObjKind::CF) {
789
19
          os << "whose name ('" << *FD
790
19
             << "') does not contain 'Copy' or 'Create'.  This violates the "
791
19
                "naming"
792
19
                " convention rules given in the Memory Management Guide for "
793
19
                "Core"
794
19
                " Foundation";
795
1
        } else if (RV->getObjKind() == ObjKind::OS) {
796
1
          std::string FuncName = FD->getNameAsString();
797
1
          os << "whose name ('" << FuncName
798
1
            << "') starts with '" << StringRef(FuncName).substr(0, 3) << "'";
799
1
        }
800
20
      }
801
49
    }
802
321
  } else {
803
321
    os << " is not referenced later in this execution path and has a retain "
804
321
          "count of +" << RV->getCount();
805
321
  }
806
374
807
374
  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
808
374
}
809
810
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
811
                               ExplodedNode *n, SymbolRef sym, bool isLeak)
812
    : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym),
813
560
      isLeak(isLeak) {
814
560
  if (!isLeak)
815
136
    addVisitor(std::make_unique<RefCountReportVisitor>(sym));
816
560
}
817
818
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
819
                               ExplodedNode *n, SymbolRef sym,
820
                               StringRef endText)
821
32
    : PathSensitiveBugReport(D, D.getDescription(), endText, n) {
822
32
823
32
  addVisitor(std::make_unique<RefCountReportVisitor>(sym));
824
32
}
825
826
123
void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
827
123
  const SourceManager& SMgr = Ctx.getSourceManager();
828
123
829
123
  if (!sym->getOriginRegion())
830
115
    return;
831
8
832
8
  auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
833
8
  if (Region) {
834
8
    const Decl *PDecl = Region->getDecl();
835
8
    if (PDecl && isa<ParmVarDecl>(PDecl)) {
836
8
      PathDiagnosticLocation ParamLocation =
837
8
          PathDiagnosticLocation::create(PDecl, SMgr);
838
8
      Location = ParamLocation;
839
8
      UniqueingLocation = ParamLocation;
840
8
      UniqueingDecl = Ctx.getLocationContext()->getDecl();
841
8
    }
842
8
  }
843
8
}
844
845
void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
846
424
                                          SymbolRef sym) {
847
  // Most bug reports are cached at the location where they occurred.
848
  // With leaks, we want to unique them by the location where they were
849
  // allocated, and only report a single path.  To do this, we need to find
850
  // the allocation site of a piece of tracked memory, which we do via a
851
  // call to GetAllocationSite.  This will walk the ExplodedGraph backwards.
852
  // Note that this is *not* the trimmed graph; we are guaranteed, however,
853
  // that all ancestor nodes that represent the allocation site have the
854
  // same SourceLocation.
855
424
  const ExplodedNode *AllocNode = nullptr;
856
424
857
424
  const SourceManager& SMgr = Ctx.getSourceManager();
858
424
859
424
  AllocationInfo AllocI =
860
424
      GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
861
424
862
424
  AllocNode = AllocI.N;
863
424
  AllocBinding = AllocI.R;
864
424
  markInteresting(AllocI.InterestingMethodContext);
865
424
866
  // Get the SourceLocation for the allocation site.
867
  // FIXME: This will crash the analyzer if an allocation comes from an
868
  // implicit call (ex: a destructor call).
869
  // (Currently there are no such allocations in Cocoa, though.)
870
424
  AllocStmt = AllocNode->getStmtForDiagnostics();
871
424
872
424
  if (!AllocStmt) {
873
8
    AllocBinding = nullptr;
874
8
    return;
875
8
  }
876
416
877
416
  PathDiagnosticLocation AllocLocation =
878
416
    PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
879
416
                                        AllocNode->getLocationContext());
880
416
  Location = AllocLocation;
881
416
882
  // Set uniqieing info, which will be used for unique the bug reports. The
883
  // leaks should be uniqued on the allocation site.
884
416
  UniqueingLocation = AllocLocation;
885
416
  UniqueingDecl = AllocNode->getLocationContext()->getDecl();
886
416
}
887
888
424
void RefLeakReport::createDescription(CheckerContext &Ctx) {
889
424
  assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
890
424
  Description.clear();
891
424
  llvm::raw_string_ostream os(Description);
892
424
  os << "Potential leak of an object";
893
424
894
424
  Optional<std::string> RegionDescription = describeRegion(AllocBinding);
895
424
  if (RegionDescription) {
896
298
    os << " stored into '" << *RegionDescription << '\'';
897
126
  } else {
898
126
899
    // If we can't figure out the name, just supply the type information.
900
126
    os << " of type '" << getPrettyTypeName(Sym->getType()) << "'";
901
126
  }
902
424
}
903
904
RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts,
905
                             ExplodedNode *n, SymbolRef sym,
906
                             CheckerContext &Ctx)
907
424
    : RefCountReport(D, LOpts, n, sym, /*isLeak=*/true) {
908
424
909
424
  deriveAllocLocation(Ctx, sym);
910
424
  if (!AllocBinding)
911
123
    deriveParamLocation(Ctx, sym);
912
424
913
424
  createDescription(Ctx);
914
424
915
424
  addVisitor(std::make_unique<RefLeakReportVisitor>(sym));
916
424
}