clang  15.0.0git
UndefCapturedBlockVarChecker.cpp
Go to the documentation of this file.
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 
14 #include "clang/AST/Attr.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class UndefCapturedBlockVarChecker
28  : public Checker< check::PostStmt<BlockExpr> > {
29  mutable std::unique_ptr<BugType> BT;
30 
31 public:
32  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
33 };
34 } // end anonymous namespace
35 
36 static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
37  const VarDecl *VD) {
38  if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))
39  if (BR->getDecl() == VD)
40  return BR;
41 
42  for (const Stmt *Child : S->children())
43  if (Child)
44  if (const DeclRefExpr *BR = FindBlockDeclRefExpr(Child, VD))
45  return BR;
46 
47  return nullptr;
48 }
49 
50 void
51 UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
52  CheckerContext &C) const {
53  if (!BE->getBlockDecl()->hasCaptures())
54  return;
55 
56  ProgramStateRef state = C.getState();
57  auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
58 
59  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
60  E = R->referenced_vars_end();
61 
62  for (; I != E; ++I) {
63  // This VarRegion is the region associated with the block; we need
64  // the one associated with the encompassing context.
65  const VarRegion *VR = I.getCapturedRegion();
66  const VarDecl *VD = VR->getDecl();
67 
68  if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage())
69  continue;
70 
71  // Get the VarRegion associated with VD in the local stack frame.
73  state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
74  if (ExplodedNode *N = C.generateErrorNode()) {
75  if (!BT)
76  BT.reset(
77  new BuiltinBug(this, "uninitialized variable captured by block"));
78 
79  // Generate a bug report.
80  SmallString<128> buf;
81  llvm::raw_svector_ostream os(buf);
82 
83  os << "Variable '" << VD->getName()
84  << "' is uninitialized when captured by block";
85 
86  auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
87  if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
88  R->addRange(Ex->getSourceRange());
91  /*EnableNullFPSuppression*/ false});
92  R->disablePathPruning();
93  // need location of block
94  C.emitReport(std::move(R));
95  }
96  }
97  }
98 }
99 
100 void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {
101  mgr.registerChecker<UndefCapturedBlockVarChecker>();
102 }
103 
104 bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager &mgr) {
105  return true;
106 }
clang::Decl::hasAttr
bool hasAttr() const
Definition: DeclBase.h:549
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
Attr.h
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
llvm::Optional
Definition: LLVM.h:40
V
#define V(N, I)
Definition: ASTContext.h:3176
BuiltinCheckerRegistration.h
CheckerManager.h
clang::BlockExpr::getBlockDecl
const BlockDecl * getBlockDecl() const
Definition: Expr.h:5982
FindBlockDeclRefExpr
static const DeclRefExpr * FindBlockDeclRefExpr(const Stmt *S, const VarDecl *VD)
Definition: UndefCapturedBlockVarChecker.cpp:36
llvm::SmallString< 128 >
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:874
clang::ento::bugreporter::TrackingKind::Thorough
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
clang::BlockDecl::hasCaptures
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
Definition: Decl.h:4327
BugType.h
clang::BlockExpr
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition: Expr.h:5970
clang::ento::bugreporter::trackStoredValue
void trackStoredValue(KnownSVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrameContext *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
CheckerContext.h
Checker.h
ExprEngine.h
clang
Definition: CalledOnceCheck.h:17
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:70
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::VarDecl::hasLocalStorage
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition: Decl.h:1099
clang::BlockExpr::getBody
const Stmt * getBody() const
Definition: Expr.cpp:2405
clang::DeclRefExpr
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1223
clang::NamedDecl::getName
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:274