blob: 26404930950907165e8e6ace211077b4555d1371 [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"
15#include "clang/Analysis/CFGVarDeclVisitor.h"
16#include "clang/Analysis/CFGStmtVisitor.h"
Ted Kremenek3871d8e2007-09-17 19:59:27 +000017#include "clang/Analysis/LocalCheckers.h"
18#include "clang/Basic/Diagnostic.h"
19#include "clang/AST/ASTContext.h"
Ted Kremenek7f49f502007-09-14 22:49:21 +000020#include "DataflowSolver.h"
21
Ted Kremenek3871d8e2007-09-17 19:59:27 +000022#include "llvm/ADT/SmallPtrSet.h"
23
Ted Kremenek7f49f502007-09-14 22:49:21 +000024using namespace clang;
25
Ted Kremenek3871d8e2007-09-17 19:59:27 +000026//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000027// Dataflow initialization logic.
Ted Kremenek3871d8e2007-09-17 19:59:27 +000028//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000029
30namespace {
31
Ted Kremenek3e039752007-09-17 17:14:52 +000032class RegisterDeclsAndExprs : public CFGVarDeclVisitor<RegisterDeclsAndExprs> {
33 UninitializedValues::AnalysisDataTy& AD;
Ted Kremenek7f49f502007-09-14 22:49:21 +000034public:
Ted Kremenek3e039752007-09-17 17:14:52 +000035 RegisterDeclsAndExprs(const CFG& cfg, UninitializedValues::AnalysisDataTy& ad)
36 : CFGVarDeclVisitor<RegisterDeclsAndExprs>(cfg), AD(ad)
37 {}
Ted Kremenek7f49f502007-09-14 22:49:21 +000038
39 void VisitVarDecl(VarDecl* D) {
Ted Kremenek3e039752007-09-17 17:14:52 +000040 if (AD.VMap.find(D) == AD.VMap.end())
Ted Kremenek334b30a2007-09-17 18:31:23 +000041 AD.VMap[D] = AD.NumDecls++;
Ted Kremenek3e039752007-09-17 17:14:52 +000042 }
43
44 void BlockStmt_VisitExpr(Expr* E) {
45 if (AD.EMap.find(E) == AD.EMap.end())
Ted Kremenek334b30a2007-09-17 18:31:23 +000046 AD.EMap[E] = AD.NumBlockExprs++;
Ted Kremenek3e039752007-09-17 17:14:52 +000047 }
Ted Kremenek7f49f502007-09-14 22:49:21 +000048};
49
50} // end anonymous namespace
51
52void UninitializedValues::InitializeValues(const CFG& cfg) {
Ted Kremenek3e039752007-09-17 17:14:52 +000053 RegisterDeclsAndExprs R(cfg,this->getAnalysisData());
54 R.VisitAllDecls();
Ted Kremenek334b30a2007-09-17 18:31:23 +000055 UninitializedValues::ValTy& V = getBlockDataMap()[&cfg.getEntry()];
56 V.DeclBV.resize(getAnalysisData().NumDecls);
57 V.ExprBV.resize(getAnalysisData().NumBlockExprs);
Ted Kremenek7f49f502007-09-14 22:49:21 +000058}
59
Ted Kremenek3871d8e2007-09-17 19:59:27 +000060//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000061// Transfer functions.
Ted Kremenek3871d8e2007-09-17 19:59:27 +000062//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +000063
64namespace {
Ted Kremenek334b30a2007-09-17 18:31:23 +000065
Ted Kremenek7f49f502007-09-14 22:49:21 +000066class TransferFuncs : public CFGStmtVisitor<TransferFuncs,bool> {
67 UninitializedValues::ValTy V;
Ted Kremenek3e039752007-09-17 17:14:52 +000068 UninitializedValues::AnalysisDataTy& AD;
Ted Kremenek7f49f502007-09-14 22:49:21 +000069public:
Ted Kremenek3e039752007-09-17 17:14:52 +000070 TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {
Ted Kremenek334b30a2007-09-17 18:31:23 +000071 V.DeclBV.resize(AD.NumDecls);
72 V.ExprBV.resize(AD.NumBlockExprs);
Ted Kremenek7f49f502007-09-14 22:49:21 +000073 }
74
75 UninitializedValues::ValTy& getVal() { return V; }
Ted Kremenek3e039752007-09-17 17:14:52 +000076
Ted Kremenek334b30a2007-09-17 18:31:23 +000077 bool VisitDeclRefExpr(DeclRefExpr* DR);
78 bool VisitBinaryOperator(BinaryOperator* B);
79 bool VisitUnaryOperator(UnaryOperator* U);
80 bool VisitStmt(Stmt* S);
81 bool VisitCallExpr(CallExpr* C);
82 bool BlockStmt_VisitExpr(Expr* E);
Ted Kremenek3871d8e2007-09-17 19:59:27 +000083 bool VisitDeclStmt(DeclStmt* D);
Ted Kremenek334b30a2007-09-17 18:31:23 +000084
85 static inline bool Initialized() { return true; }
Ted Kremenek3871d8e2007-09-17 19:59:27 +000086 static inline bool Uninitialized() { return false; }
Ted Kremenek7f49f502007-09-14 22:49:21 +000087};
Ted Kremenek334b30a2007-09-17 18:31:23 +000088
89
90bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
91 if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
92 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
Ted Kremenek3871d8e2007-09-17 19:59:27 +000093 if (AD.Observer)
94 AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD);
95
Ted Kremenek334b30a2007-09-17 18:31:23 +000096 return V.DeclBV[ AD.VMap[VD] ];
97 }
98 else
99 return Initialized();
100}
101
102bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
103 if (CFG::hasImplicitControlFlow(B)) {
104 assert ( AD.EMap.find(B) != AD.EMap.end() && "Unknown block-level expr.");
105 return V.ExprBV[ AD.EMap[B] ];
106 }
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000107
108 if (B->isAssignmentOp()) {
109 // Get the Decl for the LHS, if any
110 for (Stmt* S = B->getLHS() ;; ) {
111 if (ParenExpr* P = dyn_cast<ParenExpr>(S))
112 S = P->getSubExpr();
113 else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S))
114 if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
115 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
116 return V.DeclBV[ AD.VMap[VD] ] = Visit(B->getRHS());
117 }
118
119 break;
120 }
121 }
122
Ted Kremenek334b30a2007-09-17 18:31:23 +0000123 return VisitStmt(B);
124}
125
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000126bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
127 bool x = Initialized();
128
129 for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator())
130 if (VarDecl* VD = dyn_cast<VarDecl>(D))
131 if (Stmt* I = VD->getInit()) {
132 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
133 x = V.DeclBV[ AD.VMap[VD] ] = Visit(I);
134 }
135
136 return x;
137}
138
Ted Kremenek334b30a2007-09-17 18:31:23 +0000139bool TransferFuncs::VisitCallExpr(CallExpr* C) {
140 VisitStmt(C);
141 return Initialized();
142}
143
144bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
145 switch (U->getOpcode()) {
146 case UnaryOperator::AddrOf: {
147 // Blast through parentheses and find the decl (if any). Treat it
148 // as initialized from this point forward.
149 for (Stmt* S = U->getSubExpr() ;; )
150 if (ParenExpr* P = dyn_cast<ParenExpr>(S))
151 S = P->getSubExpr();
152 else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
153 if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
154 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
155 V.DeclBV[ AD.VMap[VD] ] = Initialized();
156 }
157 break;
158 }
159 else {
160 // Evaluate the transfer function for subexpressions, even
161 // if we cannot reason more deeply about the &-expression.
162 return Visit(U->getSubExpr());
163 }
164
165 return Initialized();
166 }
167
168 default:
169 return Visit(U->getSubExpr());
170 }
171}
172
173bool TransferFuncs::VisitStmt(Stmt* S) {
174 bool x = Initialized();
175
176 // We don't stop at the first subexpression that is Uninitialized because
177 // evaluating some subexpressions may result in propogating "Uninitialized"
178 // or "Initialized" to variables referenced in the other subexpressions.
179 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000180 if (Visit(*I) == Uninitialized())
181 x = Uninitialized();
Ted Kremenek334b30a2007-09-17 18:31:23 +0000182
183 return x;
184}
185
186bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) {
187 assert ( AD.EMap.find(E) != AD.EMap.end() );
188 return V.ExprBV[ AD.EMap[E] ] = Visit(E);
189}
190
Ted Kremenek7f49f502007-09-14 22:49:21 +0000191} // end anonymous namespace
192
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000193//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000194// Merge operator.
Ted Kremenek334b30a2007-09-17 18:31:23 +0000195//
196// In our transfer functions we take the approach that any
197// combination of unintialized values, e.g. Unitialized + ___ = Unitialized.
198//
199// Merges take the opposite approach.
200//
201// In the merge of dataflow values (for Decls) we prefer unsoundness, and
202// prefer false negatives to false positives. At merges, if a value for a
203// tracked Decl is EVER initialized in any of the predecessors we treat it as
204// initialized at the confluence point.
205//
206// For tracked CFGBlock-level expressions (such as the result of
207// short-circuit), we do the opposite merge: if a value is EVER uninitialized
208// in a predecessor we treat it as uninitalized at the confluence point.
209// The reason we do this is because dataflow values for tracked Exprs are
210// not as control-dependent as dataflow values for tracked Decls.
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000211//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000212
213namespace {
214struct Merge {
215 void operator()(UninitializedValues::ValTy& Dst,
216 UninitializedValues::ValTy& Src) {
Ted Kremenek334b30a2007-09-17 18:31:23 +0000217 assert (Dst.DeclBV.size() == Src.DeclBV.size()
218 && "Bitvector sizes do not match.");
219
220 Dst.DeclBV |= Src.DeclBV;
221
222 assert (Dst.ExprBV.size() == Src.ExprBV.size()
223 && "Bitvector sizes do not match.");
224
225 Dst.ExprBV &= Src.ExprBV;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000226 }
227};
228} // end anonymous namespace
229
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000230//===----------------------------------------------------------------------===//
231// Unitialized values checker. Scan an AST and flag variable uses
232//===----------------------------------------------------------------------===//
Ted Kremenek7f49f502007-09-14 22:49:21 +0000233
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000234UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
235
236namespace {
237
238class UninitializedValuesChecker : public UninitializedValues::ObserverTy {
239 ASTContext &Ctx;
240 Diagnostic &Diags;
241 llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned;
242
243public:
244 UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags)
245 : Ctx(ctx), Diags(diags) {}
246
247 virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V,
248 UninitializedValues::AnalysisDataTy& AD,
249 DeclRefExpr* DR, VarDecl* VD) {
250
251 assert ( AD.VMap.find(VD) != AD.VMap.end() && "Unknown VarDecl.");
252 if (V.DeclBV[ AD.VMap[VD] ] == TransferFuncs::Uninitialized())
253 if (AlreadyWarned.insert(VD))
254 Diags.Report(DR->getSourceRange().Begin(), diag::warn_uninit_val);
255 }
256};
257
258} // end anonymous namespace
259
260
261void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
Ted Kremenek7f49f502007-09-14 22:49:21 +0000262
263 typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000264
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000265 // Compute the unitialized values information.
266 UninitializedValues U;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000267 Solver S(U);
Ted Kremenek3871d8e2007-09-17 19:59:27 +0000268 S.runOnCFG(cfg);
269
270 // Scan for DeclRefExprs that use uninitialized values.
271 UninitializedValuesChecker Observer(Ctx,Diags);
272 U.getAnalysisData().Observer = &Observer;
273
274 for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
Ted Kremenek7f49f502007-09-14 22:49:21 +0000275 S.runOnBlock(&*I);
276}