clang: lib/Analysis/UninitializedValues.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
29#include "llvm/ADT/BitVector.h"
30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/PackedVector.h"
32#include "llvm/ADT/SmallBitVector.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/Support/Casting.h"
35#include
36#include
37#include
38
39using namespace clang;
40
41#define DEBUG_LOGGING 0
42
44
45
46 for (const auto *FD : RD->fields()) {
47 if (FD->isUnnamedBitField())
48 continue;
49 if (FD->isZeroSize(FD->getASTContext()))
50 continue;
51
52
53 if (const auto *FieldRD = FD->getType()->getAsRecordDecl();
55 return true;
56 }
57 return false;
58}
59
68 }
69 return false;
70}
71
72
73
74
75
76namespace {
77
78class DeclToIndex {
79 llvm::DenseMap<const VarDecl *, unsigned> map;
80
81public:
82 DeclToIndex() = default;
83
84
86
87
88 unsigned size() const { return map.size(); }
89
90
91 std::optional getValueIndex(const VarDecl *d) const;
92};
93
94}
95
96void DeclToIndex::computeMap(const DeclContext &dc) {
97 unsigned count = 0;
100 for ( ; I != E; ++I) {
103 map[vd] = count++;
104 }
105}
106
107std::optional DeclToIndex::getValueIndex(const VarDecl *d) const {
108 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
109 if (I == map.end())
110 return std::nullopt;
111 return I->second;
112}
113
114
115
116
117
118
119
124
127}
128
131}
132
133namespace {
134
135using ValueVector = llvm::PackedVector<Value, 2, llvm::SmallBitVector>;
136
137class CFGBlockValues {
138 const CFG &cfg;
140 ValueVector scratch;
141 DeclToIndex declToIndex;
142
143public:
144 CFGBlockValues(const CFG &cfg);
145
146 unsigned getNumEntries() const { return declToIndex.size(); }
147
148 void computeSetOfDeclarations(const DeclContext &dc);
149
150 ValueVector &getValueVector(const CFGBlock *block) {
152 }
153
154 void setAllScratchValues(Value V);
155 void mergeIntoScratch(ValueVector const &source, bool isFirst);
156 bool updateValueVectorWithScratch(const CFGBlock *block);
157
158 bool hasNoDeclarations() const {
159 return declToIndex.size() == 0;
160 }
161
162 void resetScratch();
163
164 ValueVector::reference operator[](const VarDecl *vd);
165
168 std::optional idx = declToIndex.getValueIndex(vd);
169 return getValueVector(block)[*idx];
170 }
171};
172
173}
174
175CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
176
177void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
178 declToIndex.computeMap(dc);
179 unsigned decls = declToIndex.size();
180 scratch.resize(decls);
182 if (!n)
183 return;
184 vals.resize(n);
185 for (auto &val : vals)
186 val.resize(decls);
187}
188
189#if DEBUG_LOGGING
190static void printVector(const CFGBlock *block, ValueVector &bv,
191 unsigned num) {
192 llvm::errs() << block->getBlockID() << " :";
193 for (const auto &i : bv)
194 llvm::errs() << ' ' << i;
195 llvm::errs() << " : " << num << '\n';
196}
197#endif
198
199void CFGBlockValues::setAllScratchValues(Value V) {
200 for (unsigned I = 0, E = scratch.size(); I != E; ++I)
201 scratch[I] = V;
202}
203
204void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
205 bool isFirst) {
206 if (isFirst)
207 scratch = source;
208 else
209 scratch |= source;
210}
211
212bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
213 ValueVector &dst = getValueVector(block);
214 bool changed = (dst != scratch);
215 if (changed)
216 dst = scratch;
217#if DEBUG_LOGGING
218 printVector(block, scratch, 0);
219#endif
220 return changed;
221}
222
223void CFGBlockValues::resetScratch() {
224 scratch.reset();
225}
226
227ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
228 return scratch[*declToIndex.getValueIndex(vd)];
229}
230
231
232
233
234
235namespace {
236
237class FindVarResult {
240
241public:
242 FindVarResult(const VarDecl *vd, const DeclRefExpr *dr) : vd(vd), dr(dr) {}
243
244 const DeclRefExpr *getDeclRefExpr() const { return dr; }
245 const VarDecl *getDecl() const { return vd; }
246};
247
248}
249
251 while (Ex) {
253 if (const auto *CE = dyn_cast(Ex)) {
254 if (CE->getCastKind() == CK_LValueBitCast) {
255 Ex = CE->getSubExpr();
256 continue;
257 }
258 }
259 break;
260 }
261 return Ex;
262}
263
264
265
267 if (const auto *DRE =
269 if (const auto *VD = dyn_cast(DRE->getDecl()))
271 return FindVarResult(VD, DRE);
272 return FindVarResult(nullptr, nullptr);
273}
274
275namespace {
276
277
278
279
280class ClassifyRefs : public StmtVisitor {
281public:
284 Use,
285 SelfInit,
286 ConstRefUse,
287 Ignore
288 };
289
290private:
292 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
293
295 return ::isTrackedVar(VD, DC);
296 }
297
298 void classify(const Expr *E, Class C);
299
300public:
302
303 void VisitDeclStmt(DeclStmt *DS);
306 void VisitCallExpr(CallExpr *CE);
307 void VisitCastExpr(CastExpr *CE);
309
310 void operator()(Stmt *S) { Visit(S); }
311
313 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
314 = Classification.find(DRE);
315 if (I != Classification.end())
316 return I->second;
317
318 const auto *VD = dyn_cast(DRE->getDecl());
320 return Ignore;
321
323 }
324};
325
326}
327
330 return nullptr;
332 const auto *DRE =
334 if (DRE && DRE->getDecl() == VD)
335 return DRE;
336 }
337 return nullptr;
338}
339
340void ClassifyRefs::classify(const Expr *E, Class C) {
341
343 if (const auto *CO = dyn_cast(E)) {
344 classify(CO->getTrueExpr(), C);
345 classify(CO->getFalseExpr(), C);
346 return;
347 }
348
349 if (const auto *BCO = dyn_cast(E)) {
350 classify(BCO->getFalseExpr(), C);
351 return;
352 }
353
354 if (const auto *OVE = dyn_cast(E)) {
355 classify(OVE->getSourceExpr(), C);
356 return;
357 }
358
359 if (const auto *ME = dyn_cast(E)) {
360 if (const auto *VD = dyn_cast(ME->getMemberDecl())) {
361 if (!VD->isStaticDataMember())
362 classify(ME->getBase(), C);
363 }
364 return;
365 }
366
367 if (const auto *BO = dyn_cast(E)) {
368 switch (BO->getOpcode()) {
369 case BO_PtrMemD:
370 case BO_PtrMemI:
371 classify(BO->getLHS(), C);
372 return;
373 case BO_Comma:
374 classify(BO->getRHS(), C);
375 return;
376 default:
377 return;
378 }
379 }
380
381 FindVarResult Var = findVar(E, DC);
382 if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
383 Classification[DRE] = std::max(Classification[DRE], C);
384}
385
386void ClassifyRefs::VisitDeclStmt(DeclStmt *DS) {
387 for (auto *DI : DS->decls()) {
388 auto *VD = dyn_cast(DI);
391 Classification[DRE] = SelfInit;
392 }
393}
394
395void ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) {
396
397
398
399
400
402 classify(BO->getLHS(), Use);
403 else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma)
404 classify(BO->getLHS(), Ignore);
405}
406
407void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) {
408
409
412}
413
416 classify(cast(S), Use);
417}
418
421}
422
426 return FTD->getTemplatedDecl()->hasTrivialBody();
427 return FD->hasTrivialBody();
428 }
429 return false;
430}
431
432void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
433
435
437 classify(CE->getArg(0), Use);
438 return;
439 }
441
442
443
444
445
447 I != E; ++I) {
448 if ((*I)->isGLValue()) {
449 if ((*I)->getType().isConstQualified())
450 classify((*I), isTrivialBody ? Ignore : ConstRefUse);
453 const auto *UO = dyn_cast(Ex);
454 if (UO && UO->getOpcode() == UO_AddrOf)
456 classify(Ex, Ignore);
457 }
458 }
459}
460
461void ClassifyRefs::VisitCastExpr(CastExpr *CE) {
462 if (CE->getCastKind() == CK_LValueToRValue)
464 else if (const auto *CSE = dyn_cast(CE)) {
465 if (CSE->getType()->isVoidType()) {
466
467
468
469 classify(CSE->getSubExpr(), Ignore);
470 }
471 }
472}
473
474
475
476
477
478namespace {
479
480class TransferFunctions : public StmtVisitor {
481 CFGBlockValues &vals;
482 const CFG &cfg;
485 const ClassifyRefs &classification;
488
489public:
490 TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
492 const ClassifyRefs &classification,
494 : vals(vals), cfg(cfg), block(block), ac(ac),
495 classification(classification), objCNoRet(ac.getASTContext()),
496 handler(handler) {}
497
498 void reportUse(const Expr *ex, const VarDecl *vd);
499 void reportConstRefUse(const Expr *ex, const VarDecl *vd);
500
502 void VisitBlockExpr(BlockExpr *be);
503 void VisitCallExpr(CallExpr *ce);
505 void VisitDeclStmt(DeclStmt *ds);
506 void VisitGCCAsmStmt(GCCAsmStmt *as);
510
512 return ::isTrackedVar(vd, cast(ac.getDecl()));
513 }
514
516 return ::findVar(ex, cast(ac.getDecl()));
517 }
518
521
524 return Use;
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
574 Queue.push_back(block);
575
576
577
579 while (!Queue.empty()) {
580 const CFGBlock *B = Queue.pop_back_val();
581
582
584 Use.setUninitAfterCall();
585
587 I != E; ++I) {
589 if (!Pred)
590 continue;
591
592 Value AtPredExit = vals.getValue(Pred, B, vd);
594
595 continue;
597 vals.getValue(B, nullptr, vd) == Uninitialized) {
598
599
600
601
602
603 Use.setUninitAfterDecl();
604 continue;
605 }
606
607 unsigned &SV = SuccsVisited[Pred->getBlockID()];
608 if (!SV) {
609
610
613 SI != SE; ++SI)
614 if (!*SI)
615 ++SV;
616 }
617
619
620
621 Queue.push_back(Pred);
622 }
623 }
624
625
626
627 for (const auto *Block : cfg) {
630 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
631 Term) {
632
633
634
640
641
642
643
644 if (isa(Term)) {
646 if ( || !isa(Label))
647
648 continue;
651 Branch.Output = 0;
652 Use.addUninitBranch(Branch);
653 } else {
657 Use.addUninitBranch(Branch);
658 }
659 }
660 }
661 }
662 }
663
664 return Use;
665 }
666};
667
668}
669
670void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
674}
675
676void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) {
680}
681
683
684 if (const auto *DS = dyn_cast(FS->getElement())) {
685 const auto *VD = cast(DS->getSingleDecl());
688 }
689}
690
691void TransferFunctions::VisitOMPExecutableDirective(
694 assert(S && "Expected non-null used-in-clause child.");
695 Visit(S);
696 }
699}
700
701void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
703 for (const auto &I : bd->captures()) {
704 const VarDecl *vd = I.getVariable();
706 continue;
707 if (I.isByRef()) {
709 continue;
710 }
711 reportUse(be, vd);
712 }
713}
714
715void TransferFunctions::VisitCallExpr(CallExpr *ce) {
717 if (Callee->hasAttr()) {
718
719
720
721
722
724 }
725 else if (Callee->hasAttr()) {
726
727
728
729
730
731
732
733 vals.setAllScratchValues(Unknown);
734 }
735 }
736}
737
738void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
739 switch (classification.get(dr)) {
740 case ClassifyRefs::Ignore:
741 break;
742 case ClassifyRefs::Use:
743 reportUse(dr, cast(dr->getDecl()));
744 break;
745 case ClassifyRefs::Init:
747 break;
748 case ClassifyRefs::SelfInit:
750 break;
751 case ClassifyRefs::ConstRefUse:
752 reportConstRefUse(dr, cast(dr->getDecl()));
753 break;
754 }
755}
756
757void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
758 if (BO->getOpcode() == BO_Assign) {
760 if (const VarDecl *VD = Var.getDecl())
762 }
763}
764
765void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
766 for (auto *DI : DS->decls()) {
767 auto *VD = dyn_cast(DI);
770
771
772
773
774
775
776
777
778
779
781 } else if (VD->getInit()) {
782
784 } else {
785
786
787
788
789
790
791
792
793
794
796 }
797 }
798 }
799}
800
801void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) {
802
804 return;
805
809
810
811
812 while (const auto *UO = dyn_cast(Ex))
814
815
816
817
821 }
822}
823
824void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
825
826
828 vals.setAllScratchValues(Unknown);
829 }
830}
831
832
833
834
835
838 const ClassifyRefs &classification,
839 llvm::BitVector &wasAnalyzed,
841 wasAnalyzed[block->getBlockID()] = true;
842 vals.resetScratch();
843
844 bool isFirst = true;
846 E = block->pred_end(); I != E; ++I) {
848 if (!pred)
849 continue;
850 if (wasAnalyzed[pred->getBlockID()]) {
851 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
852 isFirst = false;
853 }
854 }
855
856 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
857 for (const auto &I : *block) {
858 if (std::optional cs = I.getAs<CFGStmt>())
859 tf.Visit(const_cast<Stmt *>(cs->getStmt()));
860 }
862 if (auto *as = dyn_cast_or_null(terminator.getStmt()))
864 tf.Visit(as);
865 return vals.updateValueVectorWithScratch(block);
866}
867
868namespace {
869
870
871
872
873
875
876 llvm::BitVector hadUse;
877
878
879 bool hadAnyUse = false;
880
881
882 unsigned currentBlock = 0;
883
884 PruneBlocksHandler(unsigned numBlocks) : hadUse(numBlocks, false) {}
885
886 ~PruneBlocksHandler() override = default;
887
890 hadUse[currentBlock] = true;
891 hadAnyUse = true;
892 }
893
896 hadUse[currentBlock] = true;
897 hadAnyUse = true;
898 }
899
900
901
902
904 hadUse[currentBlock] = true;
905 hadAnyUse = true;
906 }
907};
908
909}
910
913 const CFG &cfg,
917 CFGBlockValues vals(cfg);
918 vals.computeSetOfDeclarations(dc);
919 if (vals.hasNoDeclarations())
920 return;
921
923
924
925 ClassifyRefs classification(ac);
927
928
930 ValueVector &vec = vals.getValueVector(&entry);
931 const unsigned n = vals.getNumEntries();
932 for (unsigned j = 0; j < n; ++j) {
934 }
935
936
938 llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
940 llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
943
945 PBH.currentBlock = block->getBlockID();
946
947
948 bool changed = runOnBlock(block, cfg, ac, vals,
949 classification, wasAnalyzed, PBH);
951 if (changed || !previouslyVisited[block->getBlockID()])
953 previouslyVisited[block->getBlockID()] = true;
954 }
955
956 if (!PBH.hadAnyUse)
957 return;
958
959
960 for (const auto *block : cfg)
961 if (PBH.hadUse[block->getBlockID()]) {
962 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
964 }
965}
966
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
static bool isAlwaysUninit(const Value v)
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc)
static const Expr * stripCasts(ASTContext &C, const Expr *Ex)
static bool isUninitialized(const Value v)
static bool isPointerToConst(const QualType &QT)
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 bool hasTrivialBody(CallExpr *CE)
static bool recordIsNotEmpty(const RecordDecl *RD)
static const DeclRefExpr * getSelfInitExpr(VarDecl *VD)
static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, const ClassifyRefs &classification, llvm::BitVector &wasAnalyzed, UninitVariablesHandler &handler)
__device__ __2f16 float c
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, method or block under analysis.
const Decl * getDecl() const
ASTContext & getASTContext() const
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isCompoundAssignmentOp(Opcode Opc)
Represents a block literal declaration, which is like an unnamed FunctionDecl.
ArrayRef< Capture > captures() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a single basic block in a source-level CFG.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
AdjacentBlocks::const_iterator const_pred_iterator
pred_iterator pred_begin()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
unsigned succ_size() const
Represents CFGBlock terminator statement.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
void VisitBlockStmts(Callback &O) const
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
bool isCallToStdMove() const
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
const CFGBlock * dequeue()
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
ASTContext & getParentASTContext() const
decl_iterator decls_end() const
decl_iterator decls_begin() const
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
DeclContext * getDeclContext()
This represents one expression.
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Represents a function declaration or definition.
Declaration of a template function.
This represents a GCC inline-assembly statement extension.
This is a basic class for representing single OpenMP executable directive.
ArrayRef< OMPClause * > clauses() const
const Stmt * getStructuredBlock() const
Returns the AST node representing OpenMP structured-block of this OpenMP executable directive,...
bool isStandaloneDirective() const
Returns whether or not this is a Standalone directive.
static llvm::iterator_range< used_clauses_child_iterator > used_clauses_children(ArrayRef< OMPClause * > Clauses)
Represents Objective-C's collection statement.
An expression that sends a message to the given Objective-C object or class.
bool isImplicitNoReturn(const ObjCMessageExpr *ME)
Return true if the given message expression is known to never return.
A (possibly-)qualified type.
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
field_range fields() const
RetTy Visit(PTR(Stmt) S, ParamTys... P)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
bool isScalarType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isVectorType() const
bool isRVVSizelessBuiltinType() const
Returns true for RVV scalable vector types.
bool isAnyPointerType() const
bool isRecordType() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementDecrementOp(Opcode Op)
A use of a variable, which might be uninitialized.
@ Always
The use is always uninitialized.
virtual void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used at the given expression.
virtual void handleSelfInit(const VarDecl *vd)
Called when the uninitialized variable analysis detects the idiom 'int x = x'.
virtual ~UninitVariablesHandler()
virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used as const refernce argument.
Represents a variable declaration or definition.
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
bool isExceptionVariable() const
Determine whether this variable is the exception variable in a C++ catch statememt or an Objective-C ...
const Expr * getInit() const
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
BlockID
The various types of blocks that can occur within a API notes file.
The JSON file list parser is used to communicate input to InstallAPI.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
U cast(CodeGen::Address addr)
@ Class
The "class" keyword introduces the elaborated-type-specifier.
A worklist implementation for forward dataflow analysis.
void enqueueSuccessors(const CFGBlock *Block)
Iterator for iterating over Stmt * arrays that contain only T *.
unsigned NumVariablesAnalyzed