Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
Line
Count
Source
1
// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- 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 checker detects blocks that capture uninitialized values.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14
#include "clang/AST/Attr.h"
15
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16
#include "clang/StaticAnalyzer/Core/Checker.h"
17
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
20
#include "llvm/ADT/SmallString.h"
21
#include "llvm/Support/raw_ostream.h"
22
#include <optional>
23
24
using namespace clang;
25
using namespace ento;
26
27
namespace {
28
class UndefCapturedBlockVarChecker
29
  : public Checker< check::PostStmt<BlockExpr> > {
30
  mutable std::unique_ptr<BugType> BT;
31
32
public:
33
  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
34
};
35
} // end anonymous namespace
36
37
static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
38
30
                                               const VarDecl *VD) {
39
30
  if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))
40
10
    if (BR->getDecl() == VD)
41
6
      return BR;
42
43
24
  for (const Stmt *Child : S->children())
44
24
    if (Child)
45
24
      if (const DeclRefExpr *BR = FindBlockDeclRefExpr(Child, VD))
46
20
        return BR;
47
48
4
  return nullptr;
49
24
}
50
51
void
52
UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
53
383
                                            CheckerContext &C) const {
54
383
  if (!BE->getBlockDecl()->hasCaptures())
55
153
    return;
56
57
230
  ProgramStateRef state = C.getState();
58
230
  auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
59
60
295
  for (auto Var : R->referenced_vars()) {
61
    // This VarRegion is the region associated with the block; we need
62
    // the one associated with the encompassing context.
63
295
    const VarRegion *VR = Var.getCapturedRegion();
64
295
    const VarDecl *VD = VR->getDecl();
65
66
295
    if (VD->hasAttr<BlocksAttr>() || 
!VD->hasLocalStorage()222
)
67
89
      continue;
68
69
    // Get the VarRegion associated with VD in the local stack frame.
70
206
    if (std::optional<UndefinedVal> V =
71
206
            state->getSVal(Var.getOriginalRegion()).getAs<UndefinedVal>()) {
72
6
      if (ExplodedNode *N = C.generateErrorNode()) {
73
6
        if (!BT)
74
4
          BT.reset(
75
4
              new BugType(this, "uninitialized variable captured by block"));
76
77
        // Generate a bug report.
78
6
        SmallString<128> buf;
79
6
        llvm::raw_svector_ostream os(buf);
80
81
6
        os << "Variable '" << VD->getName()
82
6
           << "' is uninitialized when captured by block";
83
84
6
        auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
85
6
        if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
86
6
          R->addRange(Ex->getSourceRange());
87
6
        bugreporter::trackStoredValue(*V, VR, *R,
88
6
                                      {bugreporter::TrackingKind::Thorough,
89
6
                                       /*EnableNullFPSuppression*/ false});
90
6
        R->disablePathPruning();
91
        // need location of block
92
6
        C.emitReport(std::move(R));
93
6
      }
94
6
    }
95
206
  }
96
230
}
97
98
1.27k
void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {
99
1.27k
  mgr.registerChecker<UndefCapturedBlockVarChecker>();
100
1.27k
}
101
102
2.55k
bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager &mgr) {
103
2.55k
  return true;
104
2.55k
}