29 #include "llvm/ADT/BitVector.h" 30 #include "llvm/ADT/DenseMap.h" 31 #include "llvm/ADT/None.h" 32 #include "llvm/ADT/Optional.h" 33 #include "llvm/ADT/PackedVector.h" 34 #include "llvm/ADT/SmallBitVector.h" 35 #include "llvm/ADT/SmallVector.h" 36 #include "llvm/Support/Casting.h" 40 using namespace clang;
42 #define DEBUG_LOGGING 0 61 llvm::DenseMap<const VarDecl *, unsigned> map;
64 DeclToIndex() =
default;
70 unsigned size()
const {
return map.size(); }
78 void DeclToIndex::computeMap(
const DeclContext &dc) {
82 for ( ; I != E; ++I) {
90 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
117 using ValueVector = llvm::PackedVector<Value, 2, llvm::SmallBitVector>;
119 class CFGBlockValues {
123 DeclToIndex declToIndex;
126 CFGBlockValues(
const CFG &cfg);
128 unsigned getNumEntries()
const {
return declToIndex.size(); }
130 void computeSetOfDeclarations(
const DeclContext &dc);
132 ValueVector &getValueVector(
const CFGBlock *block) {
136 void setAllScratchValues(
Value V);
137 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
138 bool updateValueVectorWithScratch(
const CFGBlock *block);
140 bool hasNoDeclarations()
const {
141 return declToIndex.size() == 0;
146 ValueVector::reference operator[](
const VarDecl *vd);
151 assert(idx.hasValue());
152 return getValueVector(block)[idx.getValue()];
158 CFGBlockValues::CFGBlockValues(
const CFG &c) : cfg(c), vals(0) {}
160 void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
161 declToIndex.computeMap(dc);
162 unsigned decls = declToIndex.size();
163 scratch.resize(decls);
164 unsigned n = cfg.getNumBlockIDs();
168 for (
auto &val : vals)
173 static void printVector(
const CFGBlock *block, ValueVector &bv,
176 for (
const auto &i : bv)
177 llvm::errs() <<
' ' << i;
178 llvm::errs() <<
" : " << num <<
'\n';
182 void CFGBlockValues::setAllScratchValues(
Value V) {
183 for (
unsigned I = 0, E = scratch.size(); I != E; ++I)
187 void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
195 bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
196 ValueVector &dst = getValueVector(block);
197 bool changed = (dst != scratch);
201 printVector(block, scratch, 0);
206 void CFGBlockValues::resetScratch() {
210 ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
212 assert(idx.hasValue());
213 return scratch[idx.getValue()];
222 class DataflowWorklist {
225 llvm::BitVector enqueuedBlocks;
229 : PO_I(view.
begin()), PO_E(view.
end()),
234 enqueuedBlocks[(*PO_I)->getBlockID()] =
false;
239 void enqueueSuccessors(
const CFGBlock *block);
245 void DataflowWorklist::enqueueSuccessors(
const CFGBlock *block) {
247 E = block->
succ_end(); I != E; ++I) {
249 if (!Successor || enqueuedBlocks[Successor->
getBlockID()])
251 worklist.push_back(Successor);
252 enqueuedBlocks[Successor->
getBlockID()] =
true;
256 const CFGBlock *DataflowWorklist::dequeue() {
261 if (!worklist.empty())
262 B = worklist.pop_back_val();
266 else if (PO_I != PO_E) {
273 assert(enqueuedBlocks[B->
getBlockID()] ==
true);
284 class FindVarResult {
291 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
292 const VarDecl *getDecl()
const {
return vd; }
300 if (
const auto *CE = dyn_cast<CastExpr>(Ex)) {
301 if (CE->getCastKind() == CK_LValueBitCast) {
302 Ex = CE->getSubExpr();
314 if (
const auto *DRE =
316 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
318 return FindVarResult(VD, DRE);
319 return FindVarResult(
nullptr,
nullptr);
327 class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
338 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
344 void classify(
const Expr *E, Class
C);
355 void operator()(
Stmt *S) { Visit(S); }
358 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
359 = Classification.find(DRE);
360 if (I != Classification.end())
363 const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
379 if (DRE && DRE->getDecl() == VD)
385 void ClassifyRefs::classify(
const Expr *E, Class
C) {
388 if (
const auto *CO = dyn_cast<ConditionalOperator>(E)) {
389 classify(CO->getTrueExpr(),
C);
390 classify(CO->getFalseExpr(),
C);
394 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
395 classify(BCO->getFalseExpr(),
C);
399 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) {
400 classify(OVE->getSourceExpr(),
C);
404 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
405 if (
const auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
406 if (!VD->isStaticDataMember())
407 classify(ME->getBase(),
C);
412 if (
const auto *BO = dyn_cast<BinaryOperator>(E)) {
413 switch (BO->getOpcode()) {
416 classify(BO->getLHS(),
C);
419 classify(BO->getRHS(),
C);
426 FindVarResult Var =
findVar(E, DC);
428 Classification[DRE] =
std::max(Classification[DRE], C);
431 void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
432 for (
auto *DI : DS->
decls()) {
433 auto *VD = dyn_cast<
VarDecl>(DI);
436 Classification[DRE] = SelfInit;
447 classify(BO->
getLHS(), Use);
449 classify(BO->
getLHS(), Ignore);
463 void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
468 classify(CE->
getArg(0), Use);
477 if ((*I)->isGLValue()) {
478 if ((*I)->getType().isConstQualified())
479 classify((*I), Ignore);
483 if (UO && UO->getOpcode() == UO_AddrOf)
484 Ex = UO->getSubExpr();
485 classify(Ex, Ignore);
490 void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
493 else if (
const auto *CSE = dyn_cast<CStyleCastExpr>(CE)) {
494 if (CSE->getType()->isVoidType()) {
498 classify(CSE->getSubExpr(), Ignore);
509 class TransferFunctions :
public StmtVisitor<TransferFunctions> {
510 CFGBlockValues &vals;
514 const ClassifyRefs &classification;
519 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
521 const ClassifyRefs &classification,
523 : vals(vals), cfg(cfg), block(block), ac(ac),
524 classification(classification), objCNoRet(ac.
getASTContext()),
600 Queue.push_back(block);
605 while (!Queue.empty()) {
606 const CFGBlock *B = Queue.pop_back_val();
618 Value AtPredExit = vals.getValue(Pred, B, vd);
633 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
647 Queue.push_back(Pred);
653 for (
const auto *Block : cfg) {
654 unsigned BlockID = Block->getBlockID();
655 const Stmt *Term = Block->getTerminator();
656 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
662 E = Block->succ_end(); I != E; ++I) {
670 if (isa<SwitchStmt>(Term)) {
672 if (!Label || !isa<SwitchCase>(Label))
682 Branch.
Output = I - Block->succ_begin();
696 void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
699 handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
704 if (
const auto *DS = dyn_cast<DeclStmt>(FS->
getElement())) {
711 void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
713 for (
const auto &I : bd->
captures()) {
714 const VarDecl *vd = I.getVariable();
725 void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
727 if (Callee->hasAttr<ReturnsTwiceAttr>()) {
735 else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
743 vals.setAllScratchValues(Unknown);
748 void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
749 switch (classification.get(dr)) {
750 case ClassifyRefs::Ignore:
752 case ClassifyRefs::Use:
753 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
755 case ClassifyRefs::Init:
758 case ClassifyRefs::SelfInit:
759 handler.handleSelfInit(cast<VarDecl>(dr->
getDecl()));
767 if (
const VarDecl *VD = Var.getDecl())
772 void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
773 for (
auto *DI : DS->
decls()) {
774 auto *VD = dyn_cast<
VarDecl>(DI);
788 }
else if (VD->getInit()) {
811 if (objCNoRet.isImplicitNoReturn(ME)) {
812 vals.setAllScratchValues(Unknown);
822 const ClassifyRefs &classification,
823 llvm::BitVector &wasAnalyzed,
830 E = block->
pred_end(); I != E; ++I) {
835 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
840 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
841 for (
const auto &I : *block) {
843 tf.Visit(const_cast<Stmt *>(cs->getStmt()));
845 return vals.updateValueVectorWithScratch(block);
856 llvm::BitVector hadUse;
859 bool hadAnyUse =
false;
862 unsigned currentBlock = 0;
864 PruneBlocksHandler(
unsigned numBlocks) : hadUse(numBlocks,
false) {}
866 ~PruneBlocksHandler()
override =
default;
868 void handleUseOfUninitVariable(
const VarDecl *vd,
870 hadUse[currentBlock] =
true;
877 void handleSelfInit(
const VarDecl *vd)
override {
878 hadUse[currentBlock] =
true;
891 CFGBlockValues vals(cfg);
892 vals.computeSetOfDeclarations(dc);
893 if (vals.hasNoDeclarations())
899 ClassifyRefs classification(ac);
904 ValueVector &vec = vals.getValueVector(&entry);
905 const unsigned n = vals.getNumEntries();
906 for (
unsigned j = 0; j < n; ++j) {
913 worklist.enqueueSuccessors(&cfg.
getEntry());
918 while (
const CFGBlock *block = worklist.dequeue()) {
922 bool changed =
runOnBlock(block, cfg, ac, vals,
923 classification, wasAnalyzed, PBH);
925 if (changed || !previouslyVisited[block->
getBlockID()])
926 worklist.enqueueSuccessors(block);
927 previouslyVisited[block->
getBlockID()] =
true;
934 for (
const auto *block : cfg)
936 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
const BlockDecl * getBlockDecl() const
bool isCallToStdMove() const
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
AdjacentBlocks::const_iterator const_pred_iterator
virtual ~UninitVariablesHandler()
succ_iterator succ_begin()
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
C Language Family Type Representation.
bool isRecordType() const
unsigned getBlockID() const
static bool isPointerToConst(const QualType &QT)
Decl - This represents one declaration (or definition), e.g.
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc)
static const Expr * stripCasts(ASTContext &C, const Expr *Ex)
unsigned succ_size() const
Represents a variable declaration or definition.
ASTContext & getASTContext() const
Defines the Objective-C statement AST node classes.
void setUninitAfterCall()
Kind getKind() const
Get the kind of uninitialized use.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function or method under analysis.
static bool isIncrementDecrementOp(Opcode Op)
static bool isAlwaysUninit(const Value v)
AdjacentBlocks::const_iterator const_succ_iterator
static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, const ClassifyRefs &classification, llvm::BitVector &wasAnalyzed, UninitVariablesHandler &handler)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
T * getAnalysis()
Return the specified analysis object, lazily running the analysis if necessary.
A builtin binary operation expression such as "x + y" or "x <= y".
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
bool isScalarType() const
Iterator for iterating over Stmt * arrays that contain only Expr *.
Expr * IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY
IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the value (including ptr->int ...
Represents a single basic block in a source-level CFG.
Pepresents a block literal declaration, which is like an unnamed FunctionDecl.
Expr - This represents one expression.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
bool isExceptionVariable() const
Determine whether this variable is the exception variable in a C++ catch statememt or an Objective-C ...
DeclContext * getDeclContext()
static FindVarResult findVar(const Expr *E, const DeclContext *DC)
If E is an expression comprising a reference to a single variable, find that variable.
static SVal getValue(SVal val, SValBuilder &svalBuilder)
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
An expression that sends a message to the given Objective-C object or class.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
A use of a variable, which might be uninitialized.
bool isConstQualified() const
Determine whether this type is const-qualified.
decl_iterator decls_begin() const
Expr * getSubExpr() const
CastKind getCastKind() const
ASTContext & getASTContext() const LLVM_READONLY
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
const Decl * getDecl() const
bool isAnyPointerType() const
std::vector< const CFGBlock * >::reverse_iterator iterator
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
bool isVectorType() const
static const DeclRefExpr * getSelfInitExpr(VarDecl *VD)
pred_iterator pred_begin()
Dataflow Directional Tag Classes.
void VisitBlockStmts(CALLBACK &O) const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
ArrayRef< Capture > captures() const
const Expr * getInit() const
void setUninitAfterDecl()
const Decl * getSingleDecl() const
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext, providing only those that are of type SpecificDecl (or a class derived from it).
The use is always uninitialized.
Represents Objective-C's collection statement.
static bool isCompoundAssignmentOp(Opcode Opc)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
ASTContext & getParentASTContext() const
__DEVICE__ int max(int __a, int __b)
A reference to a declared variable, function, enum, etc.
unsigned NumVariablesAnalyzed
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
void addUninitBranch(Branch B)
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
decl_iterator decls_end() const
static bool isUninitialized(const Value v)