24 #include "llvm/ADT/DenseMap.h" 25 #include "llvm/ADT/Optional.h" 26 #include "llvm/ADT/PackedVector.h" 27 #include "llvm/ADT/SmallBitVector.h" 28 #include "llvm/ADT/SmallVector.h" 29 #include "llvm/Support/SaveAndRestore.h" 32 using namespace clang;
34 #define DEBUG_LOGGING 0 52 llvm::DenseMap<const VarDecl *, unsigned> map;
60 unsigned size()
const {
return map.size(); }
67 void DeclToIndex::computeMap(
const DeclContext &dc) {
71 for ( ; I != E; ++I) {
79 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
105 typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
107 class CFGBlockValues {
111 DeclToIndex declToIndex;
113 CFGBlockValues(
const CFG &cfg);
115 unsigned getNumEntries()
const {
return declToIndex.size(); }
117 void computeSetOfDeclarations(
const DeclContext &dc);
118 ValueVector &getValueVector(
const CFGBlock *block) {
122 void setAllScratchValues(
Value V);
123 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
124 bool updateValueVectorWithScratch(
const CFGBlock *block);
126 bool hasNoDeclarations()
const {
127 return declToIndex.size() == 0;
132 ValueVector::reference operator[](
const VarDecl *vd);
137 assert(idx.hasValue());
138 return getValueVector(block)[idx.getValue()];
143 CFGBlockValues::CFGBlockValues(
const CFG &c) : cfg(c), vals(0) {}
145 void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
146 declToIndex.computeMap(dc);
147 unsigned decls = declToIndex.size();
148 scratch.resize(decls);
149 unsigned n = cfg.getNumBlockIDs();
153 for (
unsigned i = 0; i < n; ++i)
154 vals[i].resize(decls);
158 static void printVector(
const CFGBlock *block, ValueVector &bv,
161 for (
unsigned i = 0; i < bv.size(); ++i) {
162 llvm::errs() <<
' ' << bv[i];
164 llvm::errs() <<
" : " << num <<
'\n';
168 void CFGBlockValues::setAllScratchValues(
Value V) {
169 for (
unsigned I = 0, E = scratch.size(); I != E; ++I)
173 void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
181 bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
182 ValueVector &dst = getValueVector(block);
183 bool changed = (dst != scratch);
187 printVector(block, scratch, 0);
192 void CFGBlockValues::resetScratch() {
196 ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
198 assert(idx.hasValue());
199 return scratch[idx.getValue()];
207 class DataflowWorklist {
210 llvm::BitVector enqueuedBlocks;
213 : PO_I(view.
begin()), PO_E(view.
end()),
218 enqueuedBlocks[(*PO_I)->getBlockID()] =
false;
223 void enqueueSuccessors(
const CFGBlock *block);
228 void DataflowWorklist::enqueueSuccessors(
const clang::CFGBlock *block) {
230 E = block->
succ_end(); I != E; ++I) {
232 if (!Successor || enqueuedBlocks[Successor->
getBlockID()])
234 worklist.push_back(Successor);
235 enqueuedBlocks[Successor->
getBlockID()] =
true;
239 const CFGBlock *DataflowWorklist::dequeue() {
244 if (!worklist.empty())
245 B = worklist.pop_back_val();
249 else if (PO_I != PO_E) {
257 assert(enqueuedBlocks[B->
getBlockID()] ==
true);
267 class FindVarResult {
273 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
274 const VarDecl *getDecl()
const {
return vd; }
280 if (
const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
281 if (CE->getCastKind() == CK_LValueBitCast) {
282 Ex = CE->getSubExpr();
296 if (
const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
298 return FindVarResult(VD, DRE);
299 return FindVarResult(
nullptr,
nullptr);
305 class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
316 llvm::DenseMap<const DeclRefExpr*, Class> Classification;
322 void classify(
const Expr *E, Class C);
333 void operator()(
Stmt *S) { Visit(S); }
336 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
337 = Classification.find(DRE);
338 if (I != Classification.end())
341 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
356 if (DRE && DRE->
getDecl() == VD)
362 void ClassifyRefs::classify(
const Expr *E, Class
C) {
366 classify(CO->getTrueExpr(),
C);
367 classify(CO->getFalseExpr(),
C);
372 dyn_cast<BinaryConditionalOperator>(E)) {
373 classify(BCO->getFalseExpr(),
C);
378 classify(OVE->getSourceExpr(),
C);
382 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
383 if (
VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
384 if (!VD->isStaticDataMember())
385 classify(ME->getBase(),
C);
391 switch (BO->getOpcode()) {
394 classify(BO->getLHS(),
C);
397 classify(BO->getRHS(),
C);
404 FindVarResult Var = findVar(E, DC);
406 Classification[DRE] =
std::max(Classification[DRE], C);
409 void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
410 for (
auto *DI : DS->
decls()) {
414 Classification[DRE] = SelfInit;
425 classify(BO->
getLHS(), Use);
427 classify(BO->
getLHS(), Ignore);
441 void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
446 classify(CE->
getArg(0), Use);
455 if ((*I)->isGLValue()) {
456 if ((*I)->getType().isConstQualified())
457 classify((*I), Ignore);
459 const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
461 if (UO && UO->getOpcode() == UO_AddrOf)
462 Ex = UO->getSubExpr();
463 classify(Ex, Ignore);
468 void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
472 if (CSE->getType()->isVoidType()) {
476 classify(CSE->getSubExpr(), Ignore);
486 class TransferFunctions :
public StmtVisitor<TransferFunctions> {
487 CFGBlockValues &vals;
491 const ClassifyRefs &classification;
496 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
498 const ClassifyRefs &classification,
500 : vals(vals), cfg(cfg), block(block), ac(ac),
501 classification(classification), objCNoRet(ac.
getASTContext()),
518 FindVarResult findVar(
const Expr *ex) {
519 return ::findVar(ex, cast<DeclContext>(ac.
getDecl()));
577 Queue.push_back(block);
582 while (!Queue.empty()) {
583 const CFGBlock *B = Queue.pop_back_val();
595 Value AtPredExit = vals.getValue(Pred, B, vd);
610 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
624 Queue.push_back(Pred);
634 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->
succ_size() &&
640 E = Block->
succ_end(); I != E; ++I) {
648 if (isa<SwitchStmt>(Term)) {
650 if (!Label || !isa<SwitchCase>(Label))
673 void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
676 handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
688 void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
690 for (
const auto &I : bd->
captures()) {
691 const VarDecl *vd = I.getVariable();
702 void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
704 if (Callee->hasAttr<ReturnsTwiceAttr>()) {
712 else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
720 vals.setAllScratchValues(Unknown);
725 void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
726 switch (classification.get(dr)) {
727 case ClassifyRefs::Ignore:
729 case ClassifyRefs::Use:
730 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
732 case ClassifyRefs::Init:
735 case ClassifyRefs::SelfInit:
736 handler.handleSelfInit(cast<VarDecl>(dr->
getDecl()));
743 FindVarResult Var = findVar(BO->
getLHS());
744 if (
const VarDecl *VD = Var.getDecl())
749 void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
750 for (
auto *DI : DS->
decls()) {
788 if (objCNoRet.isImplicitNoReturn(ME)) {
789 vals.setAllScratchValues(Unknown);
799 const ClassifyRefs &classification,
800 llvm::BitVector &wasAnalyzed,
807 E = block->
pred_end(); I != E; ++I) {
812 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
817 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
821 tf.Visit(const_cast<Stmt*>(cs->getStmt()));
823 return vals.updateValueVectorWithScratch(block);
832 PruneBlocksHandler(
unsigned numBlocks)
833 : hadUse(numBlocks,
false), hadAnyUse(
false),
836 ~PruneBlocksHandler()
override {}
839 llvm::BitVector hadUse;
845 unsigned currentBlock;
847 void handleUseOfUninitVariable(
const VarDecl *vd,
849 hadUse[currentBlock] =
true;
856 void handleSelfInit(
const VarDecl *vd)
override {
857 hadUse[currentBlock] =
true;
869 CFGBlockValues vals(cfg);
870 vals.computeSetOfDeclarations(dc);
871 if (vals.hasNoDeclarations())
877 ClassifyRefs classification(ac);
882 ValueVector &vec = vals.getValueVector(&entry);
883 const unsigned n = vals.getNumEntries();
884 for (
unsigned j = 0; j < n ; ++j) {
891 worklist.enqueueSuccessors(&cfg.
getEntry());
896 while (
const CFGBlock *block = worklist.dequeue()) {
900 bool changed =
runOnBlock(block, cfg, ac, vals,
901 classification, wasAnalyzed, PBH);
903 if (changed || !previouslyVisited[block->
getBlockID()])
904 worklist.enqueueSuccessors(block);
905 previouslyVisited[block->
getBlockID()] =
true;
915 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
Defines the clang::ASTContext interface.
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...
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)
unsigned succ_size() const
VarDecl - An instance of this class is created to represent a variable declaration or definition...
ASTContext & getASTContext() const
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)
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 *.
CFGBlockListTy::const_iterator const_iterator
ConditionalOperator - The ?: ternary operator.
Expr * IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY
IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the value (including ptr->int ...
CFGBlock - Represents a single basic block in a source-level CFG.
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
Expr - This represents one expression.
CFG - 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 ...
ElementList::const_iterator const_iterator
DeclContext * getDeclContext()
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.
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr.
bool isConstQualified() const
Determine whether this type is const-qualified.
CFGTerminator getTerminator()
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class...
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
unsigned getNumBlockIDs() const
getNumBlockIDs - 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).
std::vector< const CFGBlock * >::reverse_iterator iterator
The use is always uninitialized.
Represents Objective-C's collection statement.
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
static bool isCompoundAssignmentOp(Opcode Opc)
BinaryConditionalOperator - The GNU extension to the conditional operator which allows the middle ope...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
ASTContext & getParentASTContext() const
A reference to a declared variable, function, enum, etc.
unsigned NumVariablesAnalyzed
bool isLocalVarDecl() const
isLocalVarDecl - 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)