clang API Documentation
00001 //==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements uninitialized values analysis for source-level CFGs. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include <utility> 00015 #include "llvm/ADT/Optional.h" 00016 #include "llvm/ADT/SmallVector.h" 00017 #include "llvm/ADT/PackedVector.h" 00018 #include "llvm/ADT/DenseMap.h" 00019 #include "clang/AST/Decl.h" 00020 #include "clang/Analysis/CFG.h" 00021 #include "clang/Analysis/AnalysisContext.h" 00022 #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" 00023 #include "clang/Analysis/Analyses/UninitializedValues.h" 00024 #include "llvm/Support/SaveAndRestore.h" 00025 00026 using namespace clang; 00027 00028 static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { 00029 if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && 00030 !vd->isExceptionVariable() && 00031 vd->getDeclContext() == dc) { 00032 QualType ty = vd->getType(); 00033 return ty->isScalarType() || ty->isVectorType(); 00034 } 00035 return false; 00036 } 00037 00038 //------------------------------------------------------------------------====// 00039 // DeclToIndex: a mapping from Decls we track to value indices. 00040 //====------------------------------------------------------------------------// 00041 00042 namespace { 00043 class DeclToIndex { 00044 llvm::DenseMap<const VarDecl *, unsigned> map; 00045 public: 00046 DeclToIndex() {} 00047 00048 /// Compute the actual mapping from declarations to bits. 00049 void computeMap(const DeclContext &dc); 00050 00051 /// Return the number of declarations in the map. 00052 unsigned size() const { return map.size(); } 00053 00054 /// Returns the bit vector index for a given declaration. 00055 llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const; 00056 }; 00057 } 00058 00059 void DeclToIndex::computeMap(const DeclContext &dc) { 00060 unsigned count = 0; 00061 DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()), 00062 E(dc.decls_end()); 00063 for ( ; I != E; ++I) { 00064 const VarDecl *vd = &*I; 00065 if (isTrackedVar(vd, &dc)) 00066 map[vd] = count++; 00067 } 00068 } 00069 00070 llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const { 00071 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d); 00072 if (I == map.end()) 00073 return llvm::Optional<unsigned>(); 00074 return I->second; 00075 } 00076 00077 //------------------------------------------------------------------------====// 00078 // CFGBlockValues: dataflow values for CFG blocks. 00079 //====------------------------------------------------------------------------// 00080 00081 // These values are defined in such a way that a merge can be done using 00082 // a bitwise OR. 00083 enum Value { Unknown = 0x0, /* 00 */ 00084 Initialized = 0x1, /* 01 */ 00085 Uninitialized = 0x2, /* 10 */ 00086 MayUninitialized = 0x3 /* 11 */ }; 00087 00088 static bool isUninitialized(const Value v) { 00089 return v >= Uninitialized; 00090 } 00091 static bool isAlwaysUninit(const Value v) { 00092 return v == Uninitialized; 00093 } 00094 00095 namespace { 00096 00097 typedef llvm::PackedVector<Value, 2> ValueVector; 00098 typedef std::pair<ValueVector *, ValueVector *> BVPair; 00099 00100 class CFGBlockValues { 00101 const CFG &cfg; 00102 BVPair *vals; 00103 ValueVector scratch; 00104 DeclToIndex declToIndex; 00105 00106 ValueVector &lazyCreate(ValueVector *&bv); 00107 public: 00108 CFGBlockValues(const CFG &cfg); 00109 ~CFGBlockValues(); 00110 00111 unsigned getNumEntries() const { return declToIndex.size(); } 00112 00113 void computeSetOfDeclarations(const DeclContext &dc); 00114 ValueVector &getValueVector(const CFGBlock *block, 00115 const CFGBlock *dstBlock); 00116 00117 BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate); 00118 00119 void mergeIntoScratch(ValueVector const &source, bool isFirst); 00120 bool updateValueVectorWithScratch(const CFGBlock *block); 00121 bool updateValueVectors(const CFGBlock *block, const BVPair &newVals); 00122 00123 bool hasNoDeclarations() const { 00124 return declToIndex.size() == 0; 00125 } 00126 00127 void resetScratch(); 00128 ValueVector &getScratch() { return scratch; } 00129 00130 ValueVector::reference operator[](const VarDecl *vd); 00131 }; 00132 } // end anonymous namespace 00133 00134 CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) { 00135 unsigned n = cfg.getNumBlockIDs(); 00136 if (!n) 00137 return; 00138 vals = new std::pair<ValueVector*, ValueVector*>[n]; 00139 memset((void*)vals, 0, sizeof(*vals) * n); 00140 } 00141 00142 CFGBlockValues::~CFGBlockValues() { 00143 unsigned n = cfg.getNumBlockIDs(); 00144 if (n == 0) 00145 return; 00146 for (unsigned i = 0; i < n; ++i) { 00147 delete vals[i].first; 00148 delete vals[i].second; 00149 } 00150 delete [] vals; 00151 } 00152 00153 void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { 00154 declToIndex.computeMap(dc); 00155 scratch.resize(declToIndex.size()); 00156 } 00157 00158 ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) { 00159 if (!bv) 00160 bv = new ValueVector(declToIndex.size()); 00161 return *bv; 00162 } 00163 00164 /// This function pattern matches for a '&&' or '||' that appears at 00165 /// the beginning of a CFGBlock that also (1) has a terminator and 00166 /// (2) has no other elements. If such an expression is found, it is returned. 00167 static const BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { 00168 if (block->empty()) 00169 return 0; 00170 00171 CFGElement front = block->front(); 00172 const CFGStmt *cstmt = front.getAs<CFGStmt>(); 00173 if (!cstmt) 00174 return 0; 00175 00176 const BinaryOperator *b = dyn_cast_or_null<BinaryOperator>(cstmt->getStmt()); 00177 00178 if (!b || !b->isLogicalOp()) 00179 return 0; 00180 00181 if (block->pred_size() == 2) { 00182 if (block->getTerminatorCondition() == b) { 00183 if (block->succ_size() == 2) 00184 return b; 00185 } 00186 else if (block->size() == 1) 00187 return b; 00188 } 00189 00190 return 0; 00191 } 00192 00193 ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block, 00194 const CFGBlock *dstBlock) { 00195 unsigned idx = block->getBlockID(); 00196 if (dstBlock && getLogicalOperatorInChain(block)) { 00197 if (*block->succ_begin() == dstBlock) 00198 return lazyCreate(vals[idx].first); 00199 assert(*(block->succ_begin()+1) == dstBlock); 00200 return lazyCreate(vals[idx].second); 00201 } 00202 00203 assert(vals[idx].second == 0); 00204 return lazyCreate(vals[idx].first); 00205 } 00206 00207 BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, 00208 bool shouldLazyCreate) { 00209 unsigned idx = block->getBlockID(); 00210 lazyCreate(vals[idx].first); 00211 if (shouldLazyCreate) 00212 lazyCreate(vals[idx].second); 00213 return vals[idx]; 00214 } 00215 00216 #if 0 00217 static void printVector(const CFGBlock *block, ValueVector &bv, 00218 unsigned num) { 00219 00220 llvm::errs() << block->getBlockID() << " :"; 00221 for (unsigned i = 0; i < bv.size(); ++i) { 00222 llvm::errs() << ' ' << bv[i]; 00223 } 00224 llvm::errs() << " : " << num << '\n'; 00225 } 00226 00227 static void printVector(const char *name, ValueVector const &bv) { 00228 llvm::errs() << name << " : "; 00229 for (unsigned i = 0; i < bv.size(); ++i) { 00230 llvm::errs() << ' ' << bv[i]; 00231 } 00232 llvm::errs() << "\n"; 00233 } 00234 #endif 00235 00236 void CFGBlockValues::mergeIntoScratch(ValueVector const &source, 00237 bool isFirst) { 00238 if (isFirst) 00239 scratch = source; 00240 else 00241 scratch |= source; 00242 } 00243 00244 bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) { 00245 ValueVector &dst = getValueVector(block, 0); 00246 bool changed = (dst != scratch); 00247 if (changed) 00248 dst = scratch; 00249 #if 0 00250 printVector(block, scratch, 0); 00251 #endif 00252 return changed; 00253 } 00254 00255 bool CFGBlockValues::updateValueVectors(const CFGBlock *block, 00256 const BVPair &newVals) { 00257 BVPair &vals = getValueVectors(block, true); 00258 bool changed = *newVals.first != *vals.first || 00259 *newVals.second != *vals.second; 00260 *vals.first = *newVals.first; 00261 *vals.second = *newVals.second; 00262 #if 0 00263 printVector(block, *vals.first, 1); 00264 printVector(block, *vals.second, 2); 00265 #endif 00266 return changed; 00267 } 00268 00269 void CFGBlockValues::resetScratch() { 00270 scratch.reset(); 00271 } 00272 00273 ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) { 00274 const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd); 00275 assert(idx.hasValue()); 00276 return scratch[idx.getValue()]; 00277 } 00278 00279 //------------------------------------------------------------------------====// 00280 // Worklist: worklist for dataflow analysis. 00281 //====------------------------------------------------------------------------// 00282 00283 namespace { 00284 class DataflowWorklist { 00285 SmallVector<const CFGBlock *, 20> worklist; 00286 llvm::BitVector enqueuedBlocks; 00287 public: 00288 DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} 00289 00290 void enqueueSuccessors(const CFGBlock *block); 00291 const CFGBlock *dequeue(); 00292 }; 00293 } 00294 00295 void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { 00296 unsigned OldWorklistSize = worklist.size(); 00297 for (CFGBlock::const_succ_iterator I = block->succ_begin(), 00298 E = block->succ_end(); I != E; ++I) { 00299 const CFGBlock *Successor = *I; 00300 if (!Successor || enqueuedBlocks[Successor->getBlockID()]) 00301 continue; 00302 worklist.push_back(Successor); 00303 enqueuedBlocks[Successor->getBlockID()] = true; 00304 } 00305 if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) 00306 return; 00307 00308 // Rotate the newly added blocks to the start of the worklist so that it forms 00309 // a proper queue when we pop off the end of the worklist. 00310 std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize, 00311 worklist.end()); 00312 } 00313 00314 const CFGBlock *DataflowWorklist::dequeue() { 00315 if (worklist.empty()) 00316 return 0; 00317 const CFGBlock *b = worklist.back(); 00318 worklist.pop_back(); 00319 enqueuedBlocks[b->getBlockID()] = false; 00320 return b; 00321 } 00322 00323 //------------------------------------------------------------------------====// 00324 // Transfer function for uninitialized values analysis. 00325 //====------------------------------------------------------------------------// 00326 00327 namespace { 00328 class FindVarResult { 00329 const VarDecl *vd; 00330 const DeclRefExpr *dr; 00331 public: 00332 FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {} 00333 00334 const DeclRefExpr *getDeclRefExpr() const { return dr; } 00335 const VarDecl *getDecl() const { return vd; } 00336 }; 00337 00338 class TransferFunctions : public StmtVisitor<TransferFunctions> { 00339 CFGBlockValues &vals; 00340 const CFG &cfg; 00341 AnalysisDeclContext ∾ 00342 UninitVariablesHandler *handler; 00343 00344 /// The last DeclRefExpr seen when analyzing a block. Used to 00345 /// cheat when detecting cases when the address of a variable is taken. 00346 DeclRefExpr *lastDR; 00347 00348 /// The last lvalue-to-rvalue conversion of a variable whose value 00349 /// was uninitialized. Normally this results in a warning, but it is 00350 /// possible to either silence the warning in some cases, or we 00351 /// propagate the uninitialized value. 00352 CastExpr *lastLoad; 00353 00354 /// For some expressions, we want to ignore any post-processing after 00355 /// visitation. 00356 bool skipProcessUses; 00357 00358 public: 00359 TransferFunctions(CFGBlockValues &vals, const CFG &cfg, 00360 AnalysisDeclContext &ac, 00361 UninitVariablesHandler *handler) 00362 : vals(vals), cfg(cfg), ac(ac), handler(handler), 00363 lastDR(0), lastLoad(0), 00364 skipProcessUses(false) {} 00365 00366 void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, 00367 bool isAlwaysUninit); 00368 00369 void VisitBlockExpr(BlockExpr *be); 00370 void VisitDeclStmt(DeclStmt *ds); 00371 void VisitDeclRefExpr(DeclRefExpr *dr); 00372 void VisitUnaryOperator(UnaryOperator *uo); 00373 void VisitBinaryOperator(BinaryOperator *bo); 00374 void VisitCastExpr(CastExpr *ce); 00375 void VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); 00376 void Visit(Stmt *s); 00377 00378 bool isTrackedVar(const VarDecl *vd) { 00379 return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); 00380 } 00381 00382 FindVarResult findBlockVarDecl(Expr *ex); 00383 00384 void ProcessUses(Stmt *s = 0); 00385 }; 00386 } 00387 00388 static const Expr *stripCasts(ASTContext &C, const Expr *Ex) { 00389 while (Ex) { 00390 Ex = Ex->IgnoreParenNoopCasts(C); 00391 if (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { 00392 if (CE->getCastKind() == CK_LValueBitCast) { 00393 Ex = CE->getSubExpr(); 00394 continue; 00395 } 00396 } 00397 break; 00398 } 00399 return Ex; 00400 } 00401 00402 void TransferFunctions::reportUninit(const DeclRefExpr *ex, 00403 const VarDecl *vd, bool isAlwaysUnit) { 00404 if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); 00405 } 00406 00407 FindVarResult TransferFunctions::findBlockVarDecl(Expr *ex) { 00408 if (DeclRefExpr *dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) 00409 if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) 00410 if (isTrackedVar(vd)) 00411 return FindVarResult(vd, dr); 00412 return FindVarResult(0, 0); 00413 } 00414 00415 void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs) { 00416 // This represents an initialization of the 'element' value. 00417 Stmt *element = fs->getElement(); 00418 const VarDecl *vd = 0; 00419 00420 if (DeclStmt *ds = dyn_cast<DeclStmt>(element)) { 00421 vd = cast<VarDecl>(ds->getSingleDecl()); 00422 if (!isTrackedVar(vd)) 00423 vd = 0; 00424 } else { 00425 // Initialize the value of the reference variable. 00426 const FindVarResult &res = findBlockVarDecl(cast<Expr>(element)); 00427 vd = res.getDecl(); 00428 } 00429 00430 if (vd) 00431 vals[vd] = Initialized; 00432 } 00433 00434 void TransferFunctions::VisitBlockExpr(BlockExpr *be) { 00435 const BlockDecl *bd = be->getBlockDecl(); 00436 for (BlockDecl::capture_const_iterator i = bd->capture_begin(), 00437 e = bd->capture_end() ; i != e; ++i) { 00438 const VarDecl *vd = i->getVariable(); 00439 if (!isTrackedVar(vd)) 00440 continue; 00441 if (i->isByRef()) { 00442 vals[vd] = Initialized; 00443 continue; 00444 } 00445 Value v = vals[vd]; 00446 if (handler && isUninitialized(v)) 00447 handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); 00448 } 00449 } 00450 00451 void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { 00452 // Record the last DeclRefExpr seen. This is an lvalue computation. 00453 // We use this value to later detect if a variable "escapes" the analysis. 00454 if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) 00455 if (isTrackedVar(vd)) { 00456 ProcessUses(); 00457 lastDR = dr; 00458 } 00459 } 00460 00461 void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { 00462 for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); 00463 DI != DE; ++DI) { 00464 if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) { 00465 if (isTrackedVar(vd)) { 00466 if (Expr *init = vd->getInit()) { 00467 // If the initializer consists solely of a reference to itself, we 00468 // explicitly mark the variable as uninitialized. This allows code 00469 // like the following: 00470 // 00471 // int x = x; 00472 // 00473 // to deliberately leave a variable uninitialized. Different analysis 00474 // clients can detect this pattern and adjust their reporting 00475 // appropriately, but we need to continue to analyze subsequent uses 00476 // of the variable. 00477 if (init == lastLoad) { 00478 const DeclRefExpr *DR 00479 = cast<DeclRefExpr>(stripCasts(ac.getASTContext(), 00480 lastLoad->getSubExpr())); 00481 if (DR->getDecl() == vd) { 00482 // int x = x; 00483 // Propagate uninitialized value, but don't immediately report 00484 // a problem. 00485 vals[vd] = Uninitialized; 00486 lastLoad = 0; 00487 lastDR = 0; 00488 if (handler) 00489 handler->handleSelfInit(vd); 00490 return; 00491 } 00492 } 00493 00494 // All other cases: treat the new variable as initialized. 00495 // This is a minor optimization to reduce the propagation 00496 // of the analysis, since we will have already reported 00497 // the use of the uninitialized value (which visiting the 00498 // initializer). 00499 vals[vd] = Initialized; 00500 } 00501 } 00502 } 00503 } 00504 } 00505 00506 void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { 00507 if (bo->isAssignmentOp()) { 00508 const FindVarResult &res = findBlockVarDecl(bo->getLHS()); 00509 if (const VarDecl *vd = res.getDecl()) { 00510 ValueVector::reference val = vals[vd]; 00511 if (isUninitialized(val)) { 00512 if (bo->getOpcode() != BO_Assign) 00513 reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); 00514 else 00515 val = Initialized; 00516 } 00517 } 00518 } 00519 } 00520 00521 void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { 00522 switch (uo->getOpcode()) { 00523 case clang::UO_PostDec: 00524 case clang::UO_PostInc: 00525 case clang::UO_PreDec: 00526 case clang::UO_PreInc: { 00527 const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); 00528 if (const VarDecl *vd = res.getDecl()) { 00529 assert(res.getDeclRefExpr() == lastDR); 00530 // We null out lastDR to indicate we have fully processed it 00531 // and we don't want the auto-value setting in Visit(). 00532 lastDR = 0; 00533 00534 ValueVector::reference val = vals[vd]; 00535 if (isUninitialized(val)) 00536 reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); 00537 } 00538 break; 00539 } 00540 default: 00541 break; 00542 } 00543 } 00544 00545 void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { 00546 if (ce->getCastKind() == CK_LValueToRValue) { 00547 const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); 00548 if (res.getDecl()) { 00549 assert(res.getDeclRefExpr() == lastDR); 00550 lastLoad = ce; 00551 } 00552 } 00553 else if (ce->getCastKind() == CK_NoOp || 00554 ce->getCastKind() == CK_LValueBitCast) { 00555 skipProcessUses = true; 00556 } 00557 else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) { 00558 if (cse->getType()->isVoidType()) { 00559 // e.g. (void) x; 00560 if (lastLoad == cse->getSubExpr()) { 00561 // Squelch any detected load of an uninitialized value if 00562 // we cast it to void. 00563 lastLoad = 0; 00564 lastDR = 0; 00565 } 00566 } 00567 } 00568 } 00569 00570 void TransferFunctions::Visit(clang::Stmt *s) { 00571 skipProcessUses = false; 00572 StmtVisitor<TransferFunctions>::Visit(s); 00573 if (!skipProcessUses) 00574 ProcessUses(s); 00575 } 00576 00577 void TransferFunctions::ProcessUses(Stmt *s) { 00578 // This method is typically called after visiting a CFGElement statement 00579 // in the CFG. We delay processing of reporting many loads of uninitialized 00580 // values until here. 00581 if (lastLoad) { 00582 // If we just visited the lvalue-to-rvalue cast, there is nothing 00583 // left to do. 00584 if (lastLoad == s) 00585 return; 00586 00587 const DeclRefExpr *DR = 00588 cast<DeclRefExpr>(stripCasts(ac.getASTContext(), 00589 lastLoad->getSubExpr())); 00590 const VarDecl *VD = cast<VarDecl>(DR->getDecl()); 00591 00592 // If we reach here, we may have seen a load of an uninitialized value 00593 // and it hasn't been casted to void or otherwise handled. In this 00594 // situation, report the incident. 00595 if (isUninitialized(vals[VD])) 00596 reportUninit(DR, VD, isAlwaysUninit(vals[VD])); 00597 00598 lastLoad = 0; 00599 00600 if (DR == lastDR) { 00601 lastDR = 0; 00602 return; 00603 } 00604 } 00605 00606 // Any other uses of 'lastDR' involve taking an lvalue of variable. 00607 // In this case, it "escapes" the analysis. 00608 if (lastDR && lastDR != s) { 00609 vals[cast<VarDecl>(lastDR->getDecl())] = Initialized; 00610 lastDR = 0; 00611 } 00612 } 00613 00614 //------------------------------------------------------------------------====// 00615 // High-level "driver" logic for uninitialized values analysis. 00616 //====------------------------------------------------------------------------// 00617 00618 static bool runOnBlock(const CFGBlock *block, const CFG &cfg, 00619 AnalysisDeclContext &ac, CFGBlockValues &vals, 00620 llvm::BitVector &wasAnalyzed, 00621 UninitVariablesHandler *handler = 0) { 00622 00623 wasAnalyzed[block->getBlockID()] = true; 00624 00625 if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { 00626 CFGBlock::const_pred_iterator itr = block->pred_begin(); 00627 BVPair vA = vals.getValueVectors(*itr, false); 00628 ++itr; 00629 BVPair vB = vals.getValueVectors(*itr, false); 00630 00631 BVPair valsAB; 00632 00633 if (b->getOpcode() == BO_LAnd) { 00634 // Merge the 'F' bits from the first and second. 00635 vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true); 00636 vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); 00637 valsAB.first = vA.first; 00638 valsAB.second = &vals.getScratch(); 00639 } else { 00640 // Merge the 'T' bits from the first and second. 00641 assert(b->getOpcode() == BO_LOr); 00642 vals.mergeIntoScratch(*vA.first, true); 00643 vals.mergeIntoScratch(*vB.first, false); 00644 valsAB.first = &vals.getScratch(); 00645 valsAB.second = vA.second ? vA.second : vA.first; 00646 } 00647 return vals.updateValueVectors(block, valsAB); 00648 } 00649 00650 // Default behavior: merge in values of predecessor blocks. 00651 vals.resetScratch(); 00652 bool isFirst = true; 00653 for (CFGBlock::const_pred_iterator I = block->pred_begin(), 00654 E = block->pred_end(); I != E; ++I) { 00655 const CFGBlock *pred = *I; 00656 if (wasAnalyzed[pred->getBlockID()]) { 00657 vals.mergeIntoScratch(vals.getValueVector(pred, block), isFirst); 00658 isFirst = false; 00659 } 00660 } 00661 // Apply the transfer function. 00662 TransferFunctions tf(vals, cfg, ac, handler); 00663 for (CFGBlock::const_iterator I = block->begin(), E = block->end(); 00664 I != E; ++I) { 00665 if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) { 00666 tf.Visit(const_cast<Stmt*>(cs->getStmt())); 00667 } 00668 } 00669 tf.ProcessUses(); 00670 return vals.updateValueVectorWithScratch(block); 00671 } 00672 00673 void clang::runUninitializedVariablesAnalysis( 00674 const DeclContext &dc, 00675 const CFG &cfg, 00676 AnalysisDeclContext &ac, 00677 UninitVariablesHandler &handler, 00678 UninitVariablesAnalysisStats &stats) { 00679 CFGBlockValues vals(cfg); 00680 vals.computeSetOfDeclarations(dc); 00681 if (vals.hasNoDeclarations()) 00682 return; 00683 00684 stats.NumVariablesAnalyzed = vals.getNumEntries(); 00685 00686 // Mark all variables uninitialized at the entry. 00687 const CFGBlock &entry = cfg.getEntry(); 00688 for (CFGBlock::const_succ_iterator i = entry.succ_begin(), 00689 e = entry.succ_end(); i != e; ++i) { 00690 if (const CFGBlock *succ = *i) { 00691 ValueVector &vec = vals.getValueVector(&entry, succ); 00692 const unsigned n = vals.getNumEntries(); 00693 for (unsigned j = 0; j < n ; ++j) { 00694 vec[j] = Uninitialized; 00695 } 00696 } 00697 } 00698 00699 // Proceed with the workist. 00700 DataflowWorklist worklist(cfg); 00701 llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); 00702 worklist.enqueueSuccessors(&cfg.getEntry()); 00703 llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); 00704 wasAnalyzed[cfg.getEntry().getBlockID()] = true; 00705 00706 while (const CFGBlock *block = worklist.dequeue()) { 00707 // Did the block change? 00708 bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed); 00709 ++stats.NumBlockVisits; 00710 if (changed || !previouslyVisited[block->getBlockID()]) 00711 worklist.enqueueSuccessors(block); 00712 previouslyVisited[block->getBlockID()] = true; 00713 } 00714 00715 // Run through the blocks one more time, and report uninitialized variabes. 00716 for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { 00717 const CFGBlock *block = *BI; 00718 if (wasAnalyzed[block->getBlockID()]) { 00719 runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler); 00720 ++stats.NumBlockVisits; 00721 } 00722 } 00723 } 00724 00725 UninitVariablesHandler::~UninitVariablesHandler() {}