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