1 // UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
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
7 //===----------------------------------------------------------------------===//
9 // This checker detects blocks that capture uninitialized values.
11 //===----------------------------------------------------------------------===//
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"
24 using namespace clang
;
28 class UndefCapturedBlockVarChecker
29 : public Checker
< check::PostStmt
<BlockExpr
> > {
30 const BugType BT
{this, "uninitialized variable captured by block"};
33 void checkPostStmt(const BlockExpr
*BE
, CheckerContext
&C
) const;
35 } // end anonymous namespace
37 static const DeclRefExpr
*FindBlockDeclRefExpr(const Stmt
*S
,
39 if (const DeclRefExpr
*BR
= dyn_cast
<DeclRefExpr
>(S
))
40 if (BR
->getDecl() == VD
)
43 for (const Stmt
*Child
: S
->children())
45 if (const DeclRefExpr
*BR
= FindBlockDeclRefExpr(Child
, VD
))
52 UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr
*BE
,
53 CheckerContext
&C
) const {
54 if (!BE
->getBlockDecl()->hasCaptures())
57 ProgramStateRef state
= C
.getState();
58 auto *R
= cast
<BlockDataRegion
>(C
.getSVal(BE
).getAsRegion());
60 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 const VarRegion
*VR
= Var
.getCapturedRegion();
64 const VarDecl
*VD
= VR
->getDecl();
66 if (VD
->hasAttr
<BlocksAttr
>() || !VD
->hasLocalStorage())
69 // Get the VarRegion associated with VD in the local stack frame.
70 if (std::optional
<UndefinedVal
> V
=
71 state
->getSVal(Var
.getOriginalRegion()).getAs
<UndefinedVal
>()) {
72 if (ExplodedNode
*N
= C
.generateErrorNode()) {
73 // Generate a bug report.
75 llvm::raw_svector_ostream
os(buf
);
77 os
<< "Variable '" << VD
->getName()
78 << "' is uninitialized when captured by block";
80 auto R
= std::make_unique
<PathSensitiveBugReport
>(BT
, os
.str(), N
);
81 if (const Expr
*Ex
= FindBlockDeclRefExpr(BE
->getBody(), VD
))
82 R
->addRange(Ex
->getSourceRange());
83 bugreporter::trackStoredValue(*V
, VR
, *R
,
84 {bugreporter::TrackingKind::Thorough
,
85 /*EnableNullFPSuppression*/ false});
86 R
->disablePathPruning();
87 // need location of block
88 C
.emitReport(std::move(R
));
94 void ento::registerUndefCapturedBlockVarChecker(CheckerManager
&mgr
) {
95 mgr
.registerChecker
<UndefCapturedBlockVarChecker
>();
98 bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager
&mgr
) {