blob: ce9454d0cc7d2b44ac63709a370ac0851130ed22 [file] [log] [blame]
Ted Kremenek7f49f502007-09-14 22:49:21 +00001//==- UninitializedValues.cpp - Find Unintialized Values --------*- C++ --*-==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Ted Kremenek and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements Uninitialized Values analysis for source-level CFGs.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Analysis/UninitializedValues.h"
Ted Kremenek7f49f502007-09-14 22:49:21 +000015#include "clang/Analysis/CFGStmtVisitor.h"
Ted Kremenek3871d8e2007-09-17 19:59:27 +000016#include "clang/Analysis/LocalCheckers.h"
17#include "clang/Basic/Diagnostic.h"
18#include "clang/AST/ASTContext.h"
Ted Kremenek7f49f502007-09-14 22:49:21 +000019#include "DataflowSolver.h"
20
Ted Kremenek3871d8e2007-09-17 19:59:27 +000021#include "llvm/ADT/SmallPtrSet.h"
22
Ted Kremenek7f49f502007-09-14 22:49:21 +000023using namespace clang;
24
Ted Kremenek3871d8e2007-09-17 19:59:27 +000025//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000026// Dataflow initialization logic.
Ted Kremenek3871d8e2007-09-17 19:59:27 +000027//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000028
29namespace {
30
Ted Kremenek0a03ce62007-09-17 20:49:30 +000031class RegisterDeclsAndExprs : public CFGStmtVisitor<RegisterDeclsAndExprs> {
Ted Kremenek3e039752007-09-17 17:14:52 +000032 UninitializedValues::AnalysisDataTy& AD;
Ted Kremenek7f49f502007-09-14 22:49:21 +000033public:
Ted Kremenek0a03ce62007-09-17 20:49:30 +000034 RegisterDeclsAndExprs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {}
Ted Kremenek7f49f502007-09-14 22:49:21 +000035
Ted Kremenek0a03ce62007-09-17 20:49:30 +000036 void VisitBlockVarDecl(BlockVarDecl* VD) {
37 if (AD.VMap.find(VD) == AD.VMap.end())
38 AD.VMap[VD] = AD.NumDecls++;
39 }
40
41 void VisitDeclChain(ScopedDecl* D) {
42 for (; D != NULL; D = D->getNextDeclarator())
43 if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(D))
44 VisitBlockVarDecl(VD);
Ted Kremenek3e039752007-09-17 17:14:52 +000045 }
46
47 void BlockStmt_VisitExpr(Expr* E) {
48 if (AD.EMap.find(E) == AD.EMap.end())
Ted Kremenek334b30a2007-09-17 18:31:23 +000049 AD.EMap[E] = AD.NumBlockExprs++;
Ted Kremenek0a03ce62007-09-17 20:49:30 +000050
51 Visit(E);
52 }
53
54 void VisitDeclRefExpr(DeclRefExpr* DR) {
55 VisitDeclChain(DR->getDecl());
56 }
57
58 void VisitDeclStmt(DeclStmt* S) {
59 VisitDeclChain(S->getDecl());
60 }
61
62 void VisitStmt(Stmt* S) {
63 VisitChildren(S);
64 }
65
Ted Kremenek7f49f502007-09-14 22:49:21 +000066};
67
68} // end anonymous namespace
69
70void UninitializedValues::InitializeValues(const CFG& cfg) {
Ted Kremenek0a03ce62007-09-17 20:49:30 +000071 RegisterDeclsAndExprs R(this->getAnalysisData());
72
73 for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
74 for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI!=BE; ++BI)
75 R.BlockStmt_Visit(*BI);
76
77 // Initialize the values of the last block.
Ted Kremenek334b30a2007-09-17 18:31:23 +000078 UninitializedValues::ValTy& V = getBlockDataMap()[&cfg.getEntry()];
Ted Kremenek0a03ce62007-09-17 20:49:30 +000079 V.resetValues(getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +000080}
81
Ted Kremenek3871d8e2007-09-17 19:59:27 +000082//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000083// Transfer functions.
Ted Kremenek3871d8e2007-09-17 19:59:27 +000084//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000085
86namespace {
Ted Kremenek334b30a2007-09-17 18:31:23 +000087
Ted Kremenek7f49f502007-09-14 22:49:21 +000088class TransferFuncs : public CFGStmtVisitor<TransferFuncs,bool> {
89 UninitializedValues::ValTy V;
Ted Kremenek3e039752007-09-17 17:14:52 +000090 UninitializedValues::AnalysisDataTy& AD;
Ted Kremenek7f49f502007-09-14 22:49:21 +000091public:
Ted Kremenek3e039752007-09-17 17:14:52 +000092 TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {
Ted Kremenek0a03ce62007-09-17 20:49:30 +000093 V.resetValues(AD);
Ted Kremenek7f49f502007-09-14 22:49:21 +000094 }
95
96 UninitializedValues::ValTy& getVal() { return V; }
Ted Kremenek3e039752007-09-17 17:14:52 +000097
Ted Kremenek334b30a2007-09-17 18:31:23 +000098 bool VisitDeclRefExpr(DeclRefExpr* DR);
99 bool VisitBinaryOperator(BinaryOperator* B);
100 bool VisitUnaryOperator(UnaryOperator* U);
101 bool VisitStmt(Stmt* S);
102 bool VisitCallExpr(CallExpr* C);
103 bool BlockStmt_VisitExpr(Expr* E);
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000104 bool VisitDeclStmt(DeclStmt* D);
Ted Kremenek334b30a2007-09-17 18:31:23 +0000105
106 static inline bool Initialized() { return true; }
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000107 static inline bool Uninitialized() { return false; }
Ted Kremenek7f49f502007-09-14 22:49:21 +0000108};
Ted Kremenek334b30a2007-09-17 18:31:23 +0000109
110
111bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000112 if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl())) {
Ted Kremenek334b30a2007-09-17 18:31:23 +0000113 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000114 if (AD.Observer)
115 AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD);
116
Ted Kremenek334b30a2007-09-17 18:31:23 +0000117 return V.DeclBV[ AD.VMap[VD] ];
118 }
119 else
120 return Initialized();
121}
122
123bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
124 if (CFG::hasImplicitControlFlow(B)) {
125 assert ( AD.EMap.find(B) != AD.EMap.end() && "Unknown block-level expr.");
126 return V.ExprBV[ AD.EMap[B] ];
127 }
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000128
129 if (B->isAssignmentOp()) {
130 // Get the Decl for the LHS, if any
131 for (Stmt* S = B->getLHS() ;; ) {
132 if (ParenExpr* P = dyn_cast<ParenExpr>(S))
133 S = P->getSubExpr();
134 else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S))
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000135 if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl())) {
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000136 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
137 return V.DeclBV[ AD.VMap[VD] ] = Visit(B->getRHS());
138 }
139
140 break;
141 }
142 }
143
Ted Kremenek334b30a2007-09-17 18:31:23 +0000144 return VisitStmt(B);
145}
146
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000147bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
148 bool x = Initialized();
149
150 for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator())
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000151 if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(D))
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000152 if (Stmt* I = VD->getInit()) {
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000153 assert ( AD.EMap.find(cast<Expr>(I)) !=
154 AD.EMap.end() && "Unknown Expr.");
155
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000156 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000157 x = V.DeclBV[ AD.VMap[VD] ] = V.ExprBV[ AD.EMap[cast<Expr>(I)] ];
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000158 }
159
160 return x;
161}
162
Ted Kremenek334b30a2007-09-17 18:31:23 +0000163bool TransferFuncs::VisitCallExpr(CallExpr* C) {
164 VisitStmt(C);
165 return Initialized();
166}
167
168bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
169 switch (U->getOpcode()) {
170 case UnaryOperator::AddrOf: {
171 // Blast through parentheses and find the decl (if any). Treat it
172 // as initialized from this point forward.
173 for (Stmt* S = U->getSubExpr() ;; )
174 if (ParenExpr* P = dyn_cast<ParenExpr>(S))
175 S = P->getSubExpr();
176 else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000177 if (BlockVarDecl* VD = dyn_cast<BlockVarDecl>(DR->getDecl())) {
Ted Kremenek334b30a2007-09-17 18:31:23 +0000178 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
179 V.DeclBV[ AD.VMap[VD] ] = Initialized();
180 }
181 break;
182 }
183 else {
184 // Evaluate the transfer function for subexpressions, even
185 // if we cannot reason more deeply about the &-expression.
186 return Visit(U->getSubExpr());
187 }
188
189 return Initialized();
190 }
191
192 default:
193 return Visit(U->getSubExpr());
194 }
195}
196
197bool TransferFuncs::VisitStmt(Stmt* S) {
198 bool x = Initialized();
199
200 // We don't stop at the first subexpression that is Uninitialized because
201 // evaluating some subexpressions may result in propogating "Uninitialized"
202 // or "Initialized" to variables referenced in the other subexpressions.
203 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000204 if (Visit(*I) == Uninitialized())
205 x = Uninitialized();
Ted Kremenek334b30a2007-09-17 18:31:23 +0000206
207 return x;
208}
209
210bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
211 assert ( AD.EMap.find(E) != AD.EMap.end() );
212 return V.ExprBV[ AD.EMap[E] ] = Visit(E);
213}
214
Ted Kremenek7f49f502007-09-14 22:49:21 +0000215} // end anonymous namespace
216
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000217//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000218// Merge operator.
Ted Kremenek334b30a2007-09-17 18:31:23 +0000219//
220// In our transfer functions we take the approach that any
221// combination of unintialized values, e.g. Unitialized + ___ = Unitialized.
222//
223// Merges take the opposite approach.
224//
225// In the merge of dataflow values (for Decls) we prefer unsoundness, and
226// prefer false negatives to false positives. At merges, if a value for a
227// tracked Decl is EVER initialized in any of the predecessors we treat it as
228// initialized at the confluence point.
229//
230// For tracked CFGBlock-level expressions (such as the result of
231// short-circuit), we do the opposite merge: if a value is EVER uninitialized
232// in a predecessor we treat it as uninitalized at the confluence point.
233// The reason we do this is because dataflow values for tracked Exprs are
234// not as control-dependent as dataflow values for tracked Decls.
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000235//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000236
237namespace {
238struct Merge {
239 void operator()(UninitializedValues::ValTy& Dst,
240 UninitializedValues::ValTy& Src) {
Ted Kremenek334b30a2007-09-17 18:31:23 +0000241 assert (Dst.DeclBV.size() == Src.DeclBV.size()
242 && "Bitvector sizes do not match.");
243
244 Dst.DeclBV |= Src.DeclBV;
245
246 assert (Dst.ExprBV.size() == Src.ExprBV.size()
247 && "Bitvector sizes do not match.");
248
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000249 Dst.ExprBV |= Src.ExprBV;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000250 }
251};
252} // end anonymous namespace
253
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000254//===----------------------------------------------------------------------===//
255// Unitialized values checker. Scan an AST and flag variable uses
256//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000257
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000258UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
259
260namespace {
261
262class UninitializedValuesChecker : public UninitializedValues::ObserverTy {
263 ASTContext &Ctx;
264 Diagnostic &Diags;
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000265 llvm::SmallPtrSet<BlockVarDecl*,10> AlreadyWarned;
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000266
267public:
268 UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
269 : Ctx(ctx), Diags(diags) {}
270
271 virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
272 UninitializedValues::AnalysisDataTy& AD,
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000273 DeclRefExpr* DR, BlockVarDecl* VD) {
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000274
275 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
276 if (V.DeclBV[ AD.VMap[VD] ] == TransferFuncs::Uninitialized())
277 if (AlreadyWarned.insert(VD))
278 Diags.Report(DR->getSourceRange().Begin(), diag::warn_uninit_val);
279 }
280};
281
282} // end anonymous namespace
283
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000284namespace clang {
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000285
286void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
Ted Kremenek7f49f502007-09-14 22:49:21 +0000287
288 typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000289
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000290 // Compute the unitialized values information.
291 UninitializedValues U;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000292 Solver S(U);
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000293 S.runOnCFG(cfg);
294
295 // Scan for DeclRefExprs that use uninitialized values.
296 UninitializedValuesChecker Observer(Ctx,Diags);
297 U.getAnalysisData().Observer = &Observer;
298
299 for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
Ted Kremenek7f49f502007-09-14 22:49:21 +0000300 S.runOnBlock(&*I);
301}
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000302
303}