Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//==- DeadStoresChecker.cpp - Check for stores to dead variables -*- 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 a DeadStores, a flow-sensitive checker that looks for
10
//  stores to variables that are no longer live.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/Attr.h"
17
#include "clang/AST/ParentMap.h"
18
#include "clang/AST/RecursiveASTVisitor.h"
19
#include "clang/Analysis/Analyses/LiveVariables.h"
20
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21
#include "clang/StaticAnalyzer/Core/Checker.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
23
#include "llvm/ADT/BitVector.h"
24
#include "llvm/ADT/SmallString.h"
25
#include "llvm/Support/SaveAndRestore.h"
26
27
using namespace clang;
28
using namespace ento;
29
30
namespace {
31
32
/// A simple visitor to record what VarDecls occur in EH-handling code.
33
class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
34
public:
35
  bool inEH;
36
  llvm::DenseSet<const VarDecl *> &S;
37
38
0
  bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
39
0
    SaveAndRestore<bool> inFinally(inEH, true);
40
0
    return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
41
0
  }
42
43
0
  bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
44
0
    SaveAndRestore<bool> inCatch(inEH, true);
45
0
    return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
46
0
  }
47
48
4
  bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
49
4
    SaveAndRestore<bool> inCatch(inEH, true);
50
4
    return TraverseStmt(S->getHandlerBlock());
51
4
  }
52
53
550
  bool VisitDeclRefExpr(DeclRefExpr *DR) {
54
550
    if (inEH)
55
4
      if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
56
4
        S.insert(D);
57
550
    return true;
58
550
  }
59
60
  EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
61
120
  inEH(false), S(S) {}
62
};
63
64
// FIXME: Eventually migrate into its own file, and have it managed by
65
// AnalysisManager.
66
class ReachableCode {
67
  const CFG &cfg;
68
  llvm::BitVector reachable;
69
public:
70
  ReachableCode(const CFG &cfg)
71
81
    : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
72
73
  void computeReachableBlocks();
74
75
114
  bool isReachable(const CFGBlock *block) const {
76
114
    return reachable[block->getBlockID()];
77
114
  }
78
};
79
}
80
81
81
void ReachableCode::computeReachableBlocks() {
82
81
  if (!cfg.getNumBlockIDs())
83
0
    return;
84
81
85
81
  SmallVector<const CFGBlock*, 10> worklist;
86
81
  worklist.push_back(&cfg.getEntry());
87
81
88
568
  while (!worklist.empty()) {
89
487
    const CFGBlock *block = worklist.pop_back_val();
90
487
    llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
91
487
    if (isReachable)
92
64
      continue;
93
423
    isReachable = true;
94
423
    for (CFGBlock::const_succ_iterator i = block->succ_begin(),
95
886
                                       e = block->succ_end(); i != e; 
++i463
)
96
463
      if (const CFGBlock *succ = *i)
97
406
        worklist.push_back(succ);
98
423
  }
99
81
}
100
101
static const Expr *
102
696
LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
103
727
  while (Ex) {
104
727
    const BinaryOperator *BO =
105
727
      dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
106
727
    if (!BO)
107
638
      break;
108
89
    if (BO->getOpcode() == BO_Assign) {
109
13
      Ex = BO->getRHS();
110
13
      continue;
111
13
    }
112
76
    if (BO->getOpcode() == BO_Comma) {
113
18
      Ex = BO->getRHS();
114
18
      continue;
115
18
    }
116
58
    break;
117
58
  }
118
696
  return Ex;
119
696
}
120
121
namespace {
122
class DeadStoreObs : public LiveVariables::Observer {
123
  const CFG &cfg;
124
  ASTContext &Ctx;
125
  BugReporter& BR;
126
  const CheckerBase *Checker;
127
  AnalysisDeclContext* AC;
128
  ParentMap& Parents;
129
  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
130
  std::unique_ptr<ReachableCode> reachableCode;
131
  const CFGBlock *currentBlock;
132
  std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
133
134
  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
135
136
public:
137
  DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
138
               const CheckerBase *checker, AnalysisDeclContext *ac,
139
               ParentMap &parents,
140
               llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
141
      : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
142
451
        Escaped(escaped), currentBlock(nullptr) {}
143
144
451
  ~DeadStoreObs() override {}
145
146
619
  bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
147
619
    if (Live.isLive(D))
148
438
      return true;
149
181
    // Lazily construct the set that records which VarDecls are in
150
181
    // EH code.
151
181
    if (!InEH.get()) {
152
120
      InEH.reset(new llvm::DenseSet<const VarDecl *>());
153
120
      EHCodeVisitor V(*InEH.get());
154
120
      V.TraverseStmt(AC->getBody());
155
120
    }
156
181
    // Treat all VarDecls that occur in EH code as being "always live"
157
181
    // when considering to suppress dead stores.  Frequently stores
158
181
    // are followed by reads in EH code, but we don't have the ability
159
181
    // to analyze that yet.
160
181
    return InEH->count(D);
161
181
  }
162
163
106
  bool isSuppressed(SourceRange R) {
164
106
    SourceManager &SMgr = Ctx.getSourceManager();
165
106
    SourceLocation Loc = R.getBegin();
166
106
    if (!Loc.isValid())
167
0
      return false;
168
106
169
106
    FileID FID = SMgr.getFileID(Loc);
170
106
    bool Invalid = false;
171
106
    StringRef Data = SMgr.getBufferData(FID, &Invalid);
172
106
    if (Invalid)
173
0
      return false;
174
106
175
106
    // Files autogenerated by DriverKit IIG contain some dead stores that
176
106
    // we don't want to report.
177
106
    if (Data.startswith("/* iig"))
178
2
      return true;
179
104
180
104
    return false;
181
104
  }
182
183
  void Report(const VarDecl *V, DeadStoreKind dsk,
184
116
              PathDiagnosticLocation L, SourceRange R) {
185
116
    if (Escaped.count(V))
186
2
      return;
187
114
188
114
    // Compute reachable blocks within the CFG for trivial cases
189
114
    // where a bogus dead store can be reported because itself is unreachable.
190
114
    if (!reachableCode.get()) {
191
81
      reachableCode.reset(new ReachableCode(cfg));
192
81
      reachableCode->computeReachableBlocks();
193
81
    }
194
114
195
114
    if (!reachableCode->isReachable(currentBlock))
196
8
      return;
197
106
198
106
    if (isSuppressed(R))
199
2
      return;
200
104
201
104
    SmallString<64> buf;
202
104
    llvm::raw_svector_ostream os(buf);
203
104
    const char *BugType = nullptr;
204
104
205
104
    switch (dsk) {
206
104
      case DeadInit:
207
47
        BugType = "Dead initialization";
208
47
        os << "Value stored to '" << *V
209
47
           << "' during its initialization is never read";
210
47
        break;
211
104
212
104
      case DeadIncrement:
213
21
        BugType = "Dead increment";
214
21
        LLVM_FALLTHROUGH;
215
44
      case Standard:
216
44
        if (!BugType) 
BugType = "Dead assignment"23
;
217
44
        os << "Value stored to '" << *V << "' is never read";
218
44
        break;
219
21
220
21
      case Enclosing:
221
13
        // Don't report issues in this case, e.g.: "if (x = foo())",
222
13
        // where 'x' is unused later.  We have yet to see a case where
223
13
        // this is a real bug.
224
13
        return;
225
91
    }
226
91
227
91
    BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
228
91
                       L, R);
229
91
  }
230
231
  void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
232
                    DeadStoreKind dsk,
233
201
                    const LiveVariables::LivenessValues &Live) {
234
201
235
201
    if (!VD->hasLocalStorage())
236
8
      return;
237
193
    // Reference types confuse the dead stores checker.  Skip them
238
193
    // for now.
239
193
    if (VD->getType()->getAs<ReferenceType>())
240
5
      return;
241
188
242
188
    if (!isLive(Live, VD) &&
243
188
        
!(84
VD->hasAttr<UnusedAttr>()84
||
VD->hasAttr<BlocksAttr>()84
||
244
84
          
VD->hasAttr<ObjCPreciseLifetimeAttr>()70
)) {
245
69
246
69
      PathDiagnosticLocation ExLoc =
247
69
        PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
248
69
      Report(VD, dsk, ExLoc, Val->getSourceRange());
249
69
    }
250
188
  }
251
252
  void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
253
2
                    const LiveVariables::LivenessValues& Live) {
254
2
    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
255
2
      CheckVarDecl(VD, DR, Val, dsk, Live);
256
2
  }
257
258
175
  bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
259
175
    if (B->isCompoundAssignmentOp())
260
19
      return true;
261
156
262
156
    const Expr *RHS = B->getRHS()->IgnoreParenCasts();
263
156
    const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
264
156
265
156
    if (!BRHS)
266
121
      return false;
267
35
268
35
    const DeclRefExpr *DR;
269
35
270
35
    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
271
30
      if (DR->getDecl() == VD)
272
17
        return true;
273
18
274
18
    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
275
7
      if (DR->getDecl() == VD)
276
3
        return true;
277
15
278
15
    return false;
279
15
  }
280
281
  void observeStmt(const Stmt *S, const CFGBlock *block,
282
8.33k
                   const LiveVariables::LivenessValues &Live) override {
283
8.33k
284
8.33k
    currentBlock = block;
285
8.33k
286
8.33k
    // Skip statements in macros.
287
8.33k
    if (S->getBeginLoc().isMacroID())
288
138
      return;
289
8.19k
290
8.19k
    // Only cover dead stores from regular assignments.  ++/-- dead stores
291
8.19k
    // have never flagged a real bug.
292
8.19k
    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
293
780
      if (!B->isAssignmentOp()) 
return404
; // Skip non-assignments.
294
376
295
376
      if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
296
244
        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
297
237
          // Special case: check for assigning null to a pointer.
298
237
          //  This is a common form of defensive programming.
299
237
          const Expr *RHS =
300
237
            LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
301
237
          RHS = RHS->IgnoreParenCasts();
302
237
303
237
          QualType T = VD->getType();
304
237
          if (T.isVolatileQualified())
305
2
            return;
306
235
          if (T->isPointerType() || 
T->isObjCObjectPointerType()169
) {
307
73
            if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
308
34
              return;
309
201
          }
310
201
311
201
          // Special case: self-assignments.  These are often used to shut up
312
201
          //  "unused variable" compiler warnings.
313
201
          if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
314
17
            if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
315
2
              return;
316
199
317
199
          // Otherwise, issue a warning.
318
199
          DeadStoreKind dsk = Parents.isConsumedExpr(B)
319
199
                              ? 
Enclosing24
320
199
                              : 
(isIncrement(VD,B) 175
?
DeadIncrement39
:
Standard136
);
321
199
322
199
          CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
323
199
        }
324
376
    }
325
7.41k
    else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
326
337
      if (!U->isIncrementOp() || 
U->isPrefix()109
)
327
318
        return;
328
19
329
19
      const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
330
19
      if (!parent || !isa<ReturnStmt>(parent))
331
13
        return;
332
6
333
6
      const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
334
6
335
6
      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
336
2
        CheckDeclRef(DR, U, DeadIncrement, Live);
337
6
    }
338
7.07k
    else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
339
589
      // Iterate through the decls.  Warn if any initializers are complex
340
589
      // expressions that are not live (never used).
341
589
      for (const auto *DI : DS->decls()) {
342
589
        const auto *V = dyn_cast<VarDecl>(DI);
343
589
344
589
        if (!V)
345
0
          continue;
346
589
347
589
        if (V->hasLocalStorage()) {
348
569
          // Reference types confuse the dead stores checker.  Skip them
349
569
          // for now.
350
569
          if (V->getType()->getAs<ReferenceType>())
351
11
            return;
352
558
353
558
          if (const Expr *E = V->getInit()) {
354
509
            while (const FullExpr *FE = dyn_cast<FullExpr>(E))
355
50
              E = FE->getSubExpr();
356
459
357
459
            // Look through transitive assignments, e.g.:
358
459
            // int x = y = 0;
359
459
            E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
360
459
361
459
            // Don't warn on C++ objects (yet) until we can show that their
362
459
            // constructors/destructors don't have side effects.
363
459
            if (isa<CXXConstructExpr>(E))
364
28
              return;
365
431
366
431
            // A dead initialization is a variable that is dead after it
367
431
            // is initialized.  We don't flag warnings for those variables
368
431
            // marked 'unused' or 'objc_precise_lifetime'.
369
431
            if (!isLive(Live, V) &&
370
431
                
!V->hasAttr<UnusedAttr>()93
&&
371
431
                
!V->hasAttr<ObjCPreciseLifetimeAttr>()89
) {
372
88
              // Special case: check for initializations with constants.
373
88
              //
374
88
              //  e.g. : int x = 0;
375
88
              //
376
88
              // If x is EVER assigned a new value later, don't issue
377
88
              // a warning.  This is because such initialization can be
378
88
              // due to defensive programming.
379
88
              if (E->isEvaluatable(Ctx))
380
34
                return;
381
54
382
54
              if (const DeclRefExpr *DRE =
383
7
                  dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
384
7
                if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
385
7
                  // Special case: check for initialization from constant
386
7
                  //  variables.
387
7
                  //
388
7
                  //  e.g. extern const int MyConstant;
389
7
                  //       int x = MyConstant;
390
7
                  //
391
7
                  if (VD->hasGlobalStorage() &&
392
7
                      
VD->getType().isConstQualified()2
)
393
2
                    return;
394
5
                  // Special case: check for initialization from scalar
395
5
                  //  parameters.  This is often a form of defensive
396
5
                  //  programming.  Non-scalars are still an error since
397
5
                  //  because it more likely represents an actual algorithmic
398
5
                  //  bug.
399
5
                  if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
400
5
                    return;
401
47
                }
402
47
403
47
              PathDiagnosticLocation Loc =
404
47
                PathDiagnosticLocation::create(V, BR.getSourceManager());
405
47
              Report(V, DeadInit, Loc, E->getSourceRange());
406
47
            }
407
431
          }
408
558
        }
409
589
      }
410
8.19k
  }
411
};
412
413
} // end anonymous namespace
414
415
//===----------------------------------------------------------------------===//
416
// Driver function to invoke the Dead-Stores checker on a CFG.
417
//===----------------------------------------------------------------------===//
418
419
namespace {
420
class FindEscaped {
421
public:
422
  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
423
424
7.90k
  void operator()(const Stmt *S) {
425
7.90k
    // Check for '&'. Any VarDecl whose address has been taken we treat as
426
7.90k
    // escaped.
427
7.90k
    // FIXME: What about references?
428
7.90k
    if (auto *LE = dyn_cast<LambdaExpr>(S)) {
429
51
      findLambdaReferenceCaptures(LE);
430
51
      return;
431
51
    }
432
7.85k
433
7.85k
    const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
434
7.85k
    if (!U)
435
7.51k
      return;
436
339
    if (U->getOpcode() != UO_AddrOf)
437
311
      return;
438
28
439
28
    const Expr *E = U->getSubExpr()->IgnoreParenCasts();
440
28
    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
441
26
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
442
25
        Escaped.insert(VD);
443
28
  }
444
445
  // Treat local variables captured by reference in C++ lambdas as escaped.
446
51
  void findLambdaReferenceCaptures(const LambdaExpr *LE)  {
447
51
    const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
448
51
    llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
449
51
    FieldDecl *ThisCaptureField;
450
51
    LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
451
51
452
55
    for (const LambdaCapture &C : LE->captures()) {
453
55
      if (!C.capturesVariable())
454
5
        continue;
455
50
456
50
      VarDecl *VD = C.getCapturedVar();
457
50
      const FieldDecl *FD = CaptureFields[VD];
458
50
      if (!FD)
459
0
        continue;
460
50
461
50
      // If the capture field is a reference type, it is capture-by-reference.
462
50
      if (FD->getType()->isReferenceType())
463
19
        Escaped.insert(VD);
464
50
    }
465
51
  }
466
};
467
} // end anonymous namespace
468
469
470
//===----------------------------------------------------------------------===//
471
// DeadStoresChecker
472
//===----------------------------------------------------------------------===//
473
474
namespace {
475
class DeadStoresChecker : public Checker<check::ASTCodeBody> {
476
public:
477
  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
478
467
                        BugReporter &BR) const {
479
467
480
467
    // Don't do anything for template instantiations.
481
467
    // Proving that code in a template instantiation is "dead"
482
467
    // means proving that it is dead in all instantiations.
483
467
    // This same problem exists with -Wunreachable-code.
484
467
    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
485
422
      if (FD->isTemplateInstantiation())
486
16
        return;
487
451
488
451
    if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
489
451
      CFG &cfg = *mgr.getCFG(D);
490
451
      AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
491
451
      ParentMap &pmap = mgr.getParentMap(D);
492
451
      FindEscaped FS;
493
451
      cfg.VisitBlockStmts(FS);
494
451
      DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
495
451
      L->runOnAllBlocks(A);
496
451
    }
497
451
  }
498
};
499
}
500
501
31
void ento::registerDeadStoresChecker(CheckerManager &mgr) {
502
31
  mgr.registerChecker<DeadStoresChecker>();
503
31
}
504
505
31
bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) {
506
31
  return true;
507
31
}