clang 23.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
13#include "clang/AST/Attr.h"
20#include <optional>
21
22using namespace clang;
23using namespace ento;
24
25namespace {
26class UndefCapturedBlockVarChecker
27 : public Checker< check::PostStmt<BlockExpr> > {
28 const BugType BT{this, "uninitialized variable captured by block"};
29
30public:
31 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
32};
33} // end anonymous namespace
34
35static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
36 const VarDecl *VD) {
37 if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))
38 if (BR->getDecl() == VD)
39 return BR;
40
41 for (const Stmt *Child : S->children())
42 if (Child)
43 if (const DeclRefExpr *BR = FindBlockDeclRefExpr(Child, VD))
44 return BR;
45
46 return nullptr;
47}
48
49void
50UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
51 CheckerContext &C) const {
52 if (!BE->getBlockDecl()->hasCaptures())
53 return;
54
55 ProgramStateRef state = C.getState();
56 auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
57
58 for (auto Var : R->referenced_vars()) {
59 // This VarRegion is the region associated with the block; we need
60 // the one associated with the encompassing context.
61 const VarRegion *VR = Var.getCapturedRegion();
62 const VarDecl *VD = VR->getDecl();
63
64 if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage())
65 continue;
66
67 // Get the VarRegion associated with VD in the local stack frame.
68 if (std::optional<UndefinedVal> V =
69 state->getSVal(Var.getOriginalRegion()).getAs<UndefinedVal>()) {
70 if (ExplodedNode *N = C.generateErrorNode()) {
71 auto R = std::make_unique<PathSensitiveBugReport>(
72 BT,
73 "Variable '" + Twine(VD->getName()) +
74 "' is uninitialized when captured by block",
75 N);
76 if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
77 R->addRange(Ex->getSourceRange());
79 {bugreporter::TrackingKind::Thorough,
80 /*EnableNullFPSuppression*/ false});
81 R->disablePathPruning();
82 // need location of block
83 C.emitReport(std::move(R));
84 }
85 }
86 }
87}
88
89void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {
90 mgr.registerChecker<UndefCapturedBlockVarChecker>();
91}
92
93bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager &mgr) {
94 return true;
95}
#define V(N, I)
static const DeclRefExpr * FindBlockDeclRefExpr(const Stmt *S, const VarDecl *VD)
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
Definition Decl.h:4822
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition Expr.h:6675
const Stmt * getBody() const
Definition Expr.cpp:2550
const BlockDecl * getBlockDecl() const
Definition Expr.h:6687
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
bool hasAttr() const
Definition DeclBase.h:585
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
Stmt - This represents one statement.
Definition Stmt.h:86
child_range children()
Definition Stmt.cpp:304
Represents a variable declaration or definition.
Definition Decl.h:932
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1190
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:565
const VarDecl * getDecl() const override=0
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)
Definition Address.h:327