brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.5 KiB · 2839ef0 Raw
101 lines · cpp
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-exception6//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 24using namespace clang;25using namespace ento;26 27namespace {28class UndefCapturedBlockVarChecker29  : public Checker< check::PostStmt<BlockExpr> > {30  const BugType BT{this, "uninitialized variable captured by block"};31 32public:33  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;34};35} // end anonymous namespace36 37static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,38                                               const VarDecl *VD) {39  if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))40    if (BR->getDecl() == VD)41      return BR;42 43  for (const Stmt *Child : S->children())44    if (Child)45      if (const DeclRefExpr *BR = FindBlockDeclRefExpr(Child, VD))46        return BR;47 48  return nullptr;49}50 51void52UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,53                                            CheckerContext &C) const {54  if (!BE->getBlockDecl()->hasCaptures())55    return;56 57  ProgramStateRef state = C.getState();58  auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());59 60  for (auto Var : R->referenced_vars()) {61    // This VarRegion is the region associated with the block; we need62    // the one associated with the encompassing context.63    const VarRegion *VR = Var.getCapturedRegion();64    const VarDecl *VD = VR->getDecl();65 66    if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage())67      continue;68 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.74        SmallString<128> buf;75        llvm::raw_svector_ostream os(buf);76 77        os << "Variable '" << VD->getName()78           << "' is uninitialized when captured by block";79 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 block88        C.emitReport(std::move(R));89      }90    }91  }92}93 94void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {95  mgr.registerChecker<UndefCapturedBlockVarChecker>();96}97 98bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager &mgr) {99  return true;100}101