194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//
394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//                     The LLVM Compiler Infrastructure
494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//
594fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek// This file is distributed under the University of Illinois Open Source
694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek// License. See LICENSE.TXT for details.
794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//
894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//===----------------------------------------------------------------------===//
994fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//
1094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek// This checker detects blocks that capture uninitialized values.
1194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//
1294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek//===----------------------------------------------------------------------===//
1394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
14265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis#include "ClangSACheckers.h"
152fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h"
162fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
18265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
218fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
2294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek#include "llvm/Support/raw_ostream.h"
2394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
2494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenekusing namespace clang;
259ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
2694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
2794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremeneknamespace {
2894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenekclass UndefCapturedBlockVarChecker
29ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis  : public Checker< check::PostStmt<BlockExpr> > {
306f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith mutable OwningPtr<BugType> BT;
3194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
3294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenekpublic:
33265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
3494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek};
3594fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek} // end anonymous namespace
3694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
37f4b88a45902af1802a1cb42ba48b1c474474f228John McCallstatic const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
38f4b88a45902af1802a1cb42ba48b1c474474f228John McCall                                               const VarDecl *VD) {
39f4b88a45902af1802a1cb42ba48b1c474474f228John McCall  if (const DeclRefExpr *BR = dyn_cast<DeclRefExpr>(S))
4094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    if (BR->getDecl() == VD)
4194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek      return BR;
4294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
4394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
4494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek       I!=E; ++I)
4594fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    if (const Stmt *child = *I) {
46f4b88a45902af1802a1cb42ba48b1c474474f228John McCall      const DeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
4794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek      if (BR)
4894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        return BR;
4994fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    }
5094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
5194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  return NULL;
5294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek}
5394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
5494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenekvoid
55265c674f634e99e5df1135d764e21365351372daArgyrios KyrtzidisUndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
56265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis                                            CheckerContext &C) const {
57469a1eb996e1cb0be54f9b210f836afbddcbb2ccJohn McCall  if (!BE->getBlockDecl()->hasCaptures())
5894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    return;
5994fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
608bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
6194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  const BlockDataRegion *R =
625eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek    cast<BlockDataRegion>(state->getSVal(BE,
635eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek                                         C.getLocationContext()).getAsRegion());
6494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
6594fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
6694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek                                            E = R->referenced_vars_end();
6794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
6894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  for (; I != E; ++I) {
6994fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    // This VarRegion is the region associated with the block; we need
7094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    // the one associated with the encompassing context.
71e3ce2c10c3f6ae7b26700d758de909deab190d42Ted Kremenek    const VarRegion *VR = I.getCapturedRegion();
7294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    const VarDecl *VD = VR->getDecl();
7394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
7494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
7594fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek      continue;
7694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
7794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek    // Get the VarRegion associated with VD in the local stack frame.
780dd15d78fb0c99faa5df724139ba4c16a9a345c6Ted Kremenek    if (Optional<UndefinedVal> V =
790dd15d78fb0c99faa5df724139ba4c16a9a345c6Ted Kremenek          state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
80d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek      if (ExplodedNode *N = C.generateSink()) {
8194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        if (!BT)
82265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis          BT.reset(new BuiltinBug("uninitialized variable captured by block"));
8394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
8494fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        // Generate a bug report.
85f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith        SmallString<128> buf;
8694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        llvm::raw_svector_ostream os(buf);
8794fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
88937596fc25bba3ac7519e9ffff3e4fab2c97863eTed Kremenek        os << "Variable '" << VD->getName()
89937596fc25bba3ac7519e9ffff3e4fab2c97863eTed Kremenek           << "' is uninitialized when captured by block";
9094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek
91e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks        BugReport *R = new BugReport(*BT, os.str(), N);
9294fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
9394fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek          R->addRange(Ex->getSourceRange());
940dd15d78fb0c99faa5df724139ba4c16a9a345c6Ted Kremenek        R->addVisitor(new FindLastStoreBRVisitor(*V, VR));
95ed7948b55fa4b2505f240cc5287137f451172b4cTed Kremenek        R->disablePathPruning();
9694fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek        // need location of block
97785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose        C.emitReport(R);
9894fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek      }
990dd15d78fb0c99faa5df724139ba4c16a9a345c6Ted Kremenek    }
10094fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek  }
10194fd0b8c88db9b1cd99457d3cd8cd333341dd39cTed Kremenek}
102265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis
103265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidisvoid ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) {
104265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis  mgr.registerChecker<UndefCapturedBlockVarChecker>();
105265c674f634e99e5df1135d764e21365351372daArgyrios Kyrtzidis}
106