JumpDiagnostics.cpp revision 2d88708cbe4e4ec5e04e4acb6bd7f5be68557379
15af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===// 25af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 35af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// The LLVM Compiler Infrastructure 45af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 55af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// This file is distributed under the University of Illinois Open Source 65af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// License. See LICENSE.TXT for details. 75af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 85af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===----------------------------------------------------------------------===// 95af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 105af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// This file implements the JumpScopeChecker class, which is used to diagnose 115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// jumps that enter a VLA scope in an invalid way. 125af280ce21af061f96b5b5b752746871e364ba99Chris Lattner// 135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner//===----------------------------------------------------------------------===// 145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 152d88708cbe4e4ec5e04e4acb6bd7f5be68557379John McCall#include "clang/Sema/SemaInternal.h" 16384aff8b94bb0d1ad6c5667b90621e5699815bb2John McCall#include "clang/AST/DeclCXX.h" 175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner#include "clang/AST/Expr.h" 1816f0049415ec596504891259e2a83e19871c0d52Chris Lattner#include "clang/AST/StmtObjC.h" 19972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl#include "clang/AST/StmtCXX.h" 20e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#include "llvm/ADT/BitVector.h" 215af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerusing namespace clang; 225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 235af280ce21af061f96b5b5b752746871e364ba99Chris Lattnernamespace { 245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 255af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps 265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// into VLA and other protected scopes. For example, this rejects: 275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// goto L; 285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// int a[n]; 295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// L: 305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// 315af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerclass JumpScopeChecker { 325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Sema &S; 331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// GotoScope - This is a record that we use to keep track of all of the 355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// scopes that are introduced by VLAs and other things that scope jumps like 365af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// gotos. This scope tree has nothing to do with the source scope tree, 375af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// because you can have multiple VLA scopes per compound statement, and most 385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// compound statements don't introduce any scopes. 395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner struct GotoScope { 405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for 415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// the parent scope is the function body. 425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned ParentScope; 431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 44ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall /// InDiag - The diagnostic to emit if there is a jump into this scope. 45ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned InDiag; 46ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 47ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall /// OutDiag - The diagnostic to emit if there is an indirect jump out 48ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall /// of this scope. Direct jumps always clean up their current scope 49ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall /// in an orderly way. 50ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned OutDiag; 511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner /// Loc - Location to emit the diagnostic. 535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation Loc; 541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 55ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, 56ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall SourceLocation L) 57ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} 585af280ce21af061f96b5b5b752746871e364ba99Chris Lattner }; 591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::SmallVector<GotoScope, 48> Scopes; 615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; 625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner llvm::SmallVector<Stmt*, 16> Jumps; 63ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 64ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; 65ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets; 665af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerpublic: 675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner JumpScopeChecker(Stmt *Body, Sema &S); 685af280ce21af061f96b5b5b752746871e364ba99Chris Lattnerprivate: 6943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor void BuildScopeInformation(Decl *D, unsigned &ParentScope); 705af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void BuildScopeInformation(Stmt *S, unsigned ParentScope); 715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void VerifyJumps(); 72ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall void VerifyIndirectJumps(); 73ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, 74ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall LabelStmt *Target, unsigned TargetScope); 755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner void CheckJump(Stmt *From, Stmt *To, 765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation DiagLoc, unsigned JumpDiag); 775e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall 785e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall unsigned GetDeepestCommonScope(unsigned A, unsigned B); 795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner}; 805af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} // end anonymous namespace 815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 825af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 835af280ce21af061f96b5b5b752746871e364ba99Chris LattnerJumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { 845af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Add a scope entry for function scope. 85ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); 861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 875af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Build information for the top level compound statement, so that we have a 885af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // defined scope record for every "goto" and label. 895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(Body, 0); 901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 915af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Check that all jumps we saw are kosher. 925af280ce21af061f96b5b5b752746871e364ba99Chris Lattner VerifyJumps(); 93ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall VerifyIndirectJumps(); 945af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 965e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// GetDeepestCommonScope - Finds the innermost scope enclosing the 975e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// two scopes. 985e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCallunsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { 995e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall while (A != B) { 1005e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Inner scopes are created after outer scopes and therefore have 1015e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // higher indices. 1025e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall if (A < B) { 1035e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall assert(Scopes[B].ParentScope < B); 1045e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall B = Scopes[B].ParentScope; 1055e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall } else { 1065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall assert(Scopes[A].ParentScope < A); 1075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall A = Scopes[A].ParentScope; 1085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall } 1095e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall } 1105e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall return A; 1115e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall} 1125e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall 1135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a 1145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// diagnostic that should be emitted if control goes over it. If not, return 0. 115ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallstatic std::pair<unsigned,unsigned> 116ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { 1175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { 118ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned InDiag = 0, OutDiag = 0; 1195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (VD->getType()->isVariablyModifiedType()) 120ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall InDiag = diag::note_protected_by_vla; 121ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 122ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (VD->hasAttr<BlocksAttr>()) { 123ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall InDiag = diag::note_protected_by___block; 124ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall OutDiag = diag::note_exits___block; 125ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } else if (VD->hasAttr<CleanupAttr>()) { 126ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall InDiag = diag::note_protected_by_cleanup; 127ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall OutDiag = diag::note_exits_cleanup; 128ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } else if (isCPlusPlus) { 129ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // FIXME: In C++0x, we have to check more conditions than "did we 130ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // just give it an initializer?". See 6.7p3. 131ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (VD->hasLocalStorage() && VD->hasInit()) 132ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall InDiag = diag::note_protected_by_variable_init; 133ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 134ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall CanQualType T = VD->getType()->getCanonicalTypeUnqualified(); 135025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor if (!T->isDependentType()) { 136025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor while (CanQual<ArrayType> AT = T->getAs<ArrayType>()) 137025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor T = AT->getElementType(); 138025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor if (CanQual<RecordType> RT = T->getAs<RecordType>()) 139025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) 140025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor OutDiag = diag::note_exits_dtor; 141025291b591a528d8a3f303991f65e19fa1e90a9dDouglas Gregor } 142ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 1436d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner 144ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall return std::make_pair(InDiag, OutDiag); 145ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 146ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 147ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { 1485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (TD->getUnderlyingType()->isVariablyModifiedType()) 149ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0); 1505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 1511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 152ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall return std::make_pair(0U, 0U); 1535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 1545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 15543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor/// \brief Build scope information for a declaration that is part of a DeclStmt. 15643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregorvoid JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { 15743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor bool isCPlusPlus = this->S.getLangOptions().CPlusPlus; 15843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor 15943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // If this decl causes a new scope, push and switch to it. 16043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor std::pair<unsigned,unsigned> Diags 16143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor = GetDiagForGotoScopeDecl(D, isCPlusPlus); 16243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor if (Diags.first || Diags.second) { 16343dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, 16443dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor D->getLocation())); 16543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor ParentScope = Scopes.size()-1; 16643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor } 16743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor 16843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // If the decl has an initializer, walk it with the potentially new 16943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // scope we just installed. 17043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor if (VarDecl *VD = dyn_cast<VarDecl>(D)) 17143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor if (Expr *Init = VD->getInit()) 17243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor BuildScopeInformation(Init, ParentScope); 17343dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor} 1745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 1755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// BuildScopeInformation - The statements from CI to CE are known to form a 1765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// coherent VLA scope with a specified parent node. Walk through the 1775af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively 1785af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// walking the AST as needed. 1795af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { 18043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor bool SkipFirstSubStmt = false; 18143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor 1825af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If we found a label, remember that it is in ParentScope scope. 183ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall switch (S->getStmtClass()) { 184ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall case Stmt::AddrLabelExprClass: 185ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); 186ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall break; 187ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 188ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall case Stmt::IndirectGotoStmtClass: 1895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner LabelAndGotoScopes[S] = ParentScope; 190ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); 191ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall break; 192ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 193ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall case Stmt::SwitchStmtClass: 19443dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // Evaluate the condition variable before entering the scope of the switch 19543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // statement. 19643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { 19743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor BuildScopeInformation(Var, ParentScope); 19843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor SkipFirstSubStmt = true; 19943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor } 20043dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor // Fall through 20143dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor 20243dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor case Stmt::GotoStmtClass: 2035af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Remember both what scope a goto is in as well as the fact that we have 2045af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // it. This makes the second scan not have to walk the AST again. 2055af280ce21af061f96b5b5b752746871e364ba99Chris Lattner LabelAndGotoScopes[S] = ParentScope; 2065af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Jumps.push_back(S); 207ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall break; 208ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 209ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall default: 210ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall break; 2115af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2135af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; 2145af280ce21af061f96b5b5b752746871e364ba99Chris Lattner ++CI) { 21543dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor if (SkipFirstSubStmt) { 21643dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor SkipFirstSubStmt = false; 21743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor continue; 21843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor } 21943dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor 2205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Stmt *SubStmt = *CI; 2215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (SubStmt == 0) continue; 2221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 22397ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall // Cases, labels, and defaults aren't "scope parents". It's also 22497ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall // important to handle these iteratively instead of recursively in 22597ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall // order to avoid blowing out the stack. 22697ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall while (true) { 22797ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall Stmt *Next; 22897ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall if (isa<CaseStmt>(SubStmt)) 22997ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall Next = cast<CaseStmt>(SubStmt)->getSubStmt(); 23097ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall else if (isa<DefaultStmt>(SubStmt)) 23197ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall Next = cast<DefaultStmt>(SubStmt)->getSubStmt(); 23297ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall else if (isa<LabelStmt>(SubStmt)) 23397ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall Next = cast<LabelStmt>(SubStmt)->getSubStmt(); 23497ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall else 23597ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall break; 23697ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall 23797ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall LabelAndGotoScopes[SubStmt] = ParentScope; 23897ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall SubStmt = Next; 23997ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall } 24097ba481f3f45e5b63b4a354bfb471ce146b7de57John McCall 2415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // If this is a declstmt with a VLA definition, it defines a scope from here 2425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // to the end of the containing context. 2435af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { 2446d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner // The decl statement creates a scope if any of the decls in it are VLAs 2456d97e5e4b7abdae710c2548b51f4ed0298e86d80Chris Lattner // or have the cleanup attribute. 2465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 24743dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor I != E; ++I) 24843dec6bbde2d0a16c35978983761c8b7030c8e18Douglas Gregor BuildScopeInformation(*I, ParentScope); 2495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 2505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Disallow jumps into any part of an @try statement by pushing a scope and 2535af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // walking all sub-stmts in that scope. 2545af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { 2555af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Recursively walk the AST for the @try part. 256ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Scopes.push_back(GotoScope(ParentScope, 257ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_protected_by_objc_try, 258ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_objc_try, 2595af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AT->getAtTryLoc())); 2605af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (Stmt *TryPart = AT->getTryBody()) 2615af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(TryPart, Scopes.size()-1); 2625af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 2635af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Jump from the catch to the finally or try is not valid. 2648f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { 2658f5e3dd32e443768d9dbbad7191e123e6733750cDouglas Gregor ObjCAtCatchStmt *AC = AT->getCatchStmt(I); 2665af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope, 2675af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::note_protected_by_objc_catch, 268ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_objc_catch, 2695af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AC->getAtCatchLoc())); 2701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // @catches are nested and it isn't 2715af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); 2725af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2745af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Jump from the finally to the try or catch is not valid. 2755af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { 2765af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Scopes.push_back(GotoScope(ParentScope, 2775af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::note_protected_by_objc_finally, 278ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_objc_finally, 2795af280ce21af061f96b5b5b752746871e364ba99Chris Lattner AF->getAtFinallyLoc())); 2805af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(AF, Scopes.size()-1); 2815af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2835af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 2845af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 2851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 28646c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Disallow jumps into the protected statement of an @synchronized, but 28746c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // allow jumps into the object expression it protects. 28846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ 28946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Recursively walk the AST for the @synchronized object expr, it is 29046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // evaluated in the normal scope. 29146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner BuildScopeInformation(AS->getSynchExpr(), ParentScope); 2921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 29346c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // Recursively walk the AST for the @synchronized part, protected by a new 29446c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner // scope. 29546c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner Scopes.push_back(GotoScope(ParentScope, 29646c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner diag::note_protected_by_objc_synchronized, 297ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_objc_synchronized, 29846c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner AS->getAtSynchronizedLoc())); 29946c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); 30046c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner continue; 30146c3c4ba78766ac0f1c5ec631b424773e21f5271Chris Lattner } 302972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 303972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // Disallow jumps into any part of a C++ try statement. This is pretty 304972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // much the same as for Obj-C. 305972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { 306ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Scopes.push_back(GotoScope(ParentScope, 307ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_protected_by_cxx_try, 308ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_cxx_try, 309972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl TS->getSourceRange().getBegin())); 310972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl if (Stmt *TryBlock = TS->getTryBlock()) 311972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl BuildScopeInformation(TryBlock, Scopes.size()-1); 312972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 313972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl // Jump from the catch into the try is not allowed either. 3141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { 315972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl CXXCatchStmt *CS = TS->getHandler(I); 316972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl Scopes.push_back(GotoScope(ParentScope, 317972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl diag::note_protected_by_cxx_catch, 318ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::note_exits_cxx_catch, 319972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl CS->getSourceRange().getBegin())); 320972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); 321972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl } 322972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 323972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl continue; 324972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl } 325972041f45bdf8df7ea447221292d7827466ba94bSebastian Redl 3265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Recursively walk the AST. 3275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner BuildScopeInformation(SubStmt, ParentScope); 3285af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 3295af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 3305af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 3315af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// VerifyJumps - Verify each element of the Jumps array to see if they are 3325af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// valid, emitting diagnostics if not. 3335af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::VerifyJumps() { 3345af280ce21af061f96b5b5b752746871e364ba99Chris Lattner while (!Jumps.empty()) { 3355af280ce21af061f96b5b5b752746871e364ba99Chris Lattner Stmt *Jump = Jumps.pop_back_val(); 3361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // With a goto, 3385af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { 3395af280ce21af061f96b5b5b752746871e364ba99Chris Lattner CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), 3405af280ce21af061f96b5b5b752746871e364ba99Chris Lattner diag::err_goto_into_protected_scope); 3415af280ce21af061f96b5b5b752746871e364ba99Chris Lattner continue; 3425af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 3431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 344ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall SwitchStmt *SS = cast<SwitchStmt>(Jump); 345ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (SwitchCase *SC = SS->getSwitchCaseList(); SC; 346ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall SC = SC->getNextSwitchCase()) { 347ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); 348ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall CheckJump(SS, SC, SC->getLocStart(), 349ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::err_switch_into_protected_scope); 3505af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 351ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 352ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall} 353ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 3545e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// VerifyIndirectJumps - Verify whether any possible indirect jump 3555e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// might cross a protection boundary. Unlike direct jumps, indirect 3565e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// jumps count cleanups as protection boundaries: since there's no 3575e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// way to know where the jump is going, we can't implicitly run the 3585e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// right cleanups the way we can with direct jumps. 3595e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// 3605e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Thus, an indirect jump is "trivial" if it bypasses no 3615e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// initializations and no teardowns. More formally, an indirect jump 3625e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// from A to B is trivial if the path out from A to DCA(A,B) is 3635e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// trivial and the path in from DCA(A,B) to B is trivial, where 3645e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// DCA(A,B) is the deepest common ancestor of A and B. 3655e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Jump-triviality is transitive but asymmetric. 366ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall/// 367ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall/// A path in is trivial if none of the entered scopes have an InDiag. 368ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall/// A path out is trivial is none of the exited scopes have an OutDiag. 3695e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// 3705e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Under these definitions, this function checks that the indirect 3715e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// jump between A and B is trivial for every indirect goto statement A 3725e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// and every label B whose address was taken in the function. 373ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallvoid JumpScopeChecker::VerifyIndirectJumps() { 374ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (IndirectJumps.empty()) return; 375ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 376ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // If there aren't any address-of-label expressions in this function, 377ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // complain about the first indirect goto. 378ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (IndirectJumpTargets.empty()) { 379ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall S.Diag(IndirectJumps[0]->getGotoLoc(), 380ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall diag::err_indirect_goto_without_addrlabel); 381ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall return; 382ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 383ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 3845e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Collect a single representative of every scope containing an 3855e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // indirect goto. For most code bases, this substantially cuts 3865e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // down on the number of jump sites we'll have to consider later. 387ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; 388ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::SmallVector<JumpScope, 32> JumpScopes; 389ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall { 390ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; 391ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator 392ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { 393ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall IndirectGotoStmt *IG = *I; 394ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall assert(LabelAndGotoScopes.count(IG) && 395ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall "indirect jump didn't get added to scopes?"); 396ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned IGScope = LabelAndGotoScopes[IG]; 397ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; 398ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (!Entry) Entry = IG; 399ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 400ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall JumpScopes.reserve(JumpScopesMap.size()); 401ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator 402ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) 403ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall JumpScopes.push_back(*I); 404ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 405ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 4065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Collect a single representative of every scope containing a 4075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // label whose address was taken somewhere in the function. 4085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // For most code bases, there will be only one such scope. 409ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::DenseMap<unsigned, LabelStmt*> TargetScopes; 410ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (llvm::SmallVectorImpl<LabelStmt*>::iterator 411ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); 412ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall I != E; ++I) { 413ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall LabelStmt *TheLabel = *I; 414ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall assert(LabelAndGotoScopes.count(TheLabel) && 415ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall "Referenced label didn't get added to scopes?"); 416ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned LabelScope = LabelAndGotoScopes[TheLabel]; 417ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall LabelStmt *&Target = TargetScopes[LabelScope]; 418ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (!Target) Target = TheLabel; 419ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 420ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 4215e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // For each target scope, make sure it's trivially reachable from 4225e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // every scope containing a jump site. 4235e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // 4245e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // A path between scopes always consists of exitting zero or more 4255e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // scopes, then entering zero or more scopes. We build a set of 4265e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // of scopes S from which the target scope can be trivially 4275e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // entered, then verify that every jump scope can be trivially 4285e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // exitted to reach a scope in S. 429ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall llvm::BitVector Reachable(Scopes.size(), false); 430ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (llvm::DenseMap<unsigned,LabelStmt*>::iterator 431ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { 432ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned TargetScope = TI->first; 433ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall LabelStmt *TargetLabel = TI->second; 434ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 435ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Reachable.reset(); 436ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 437ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Mark all the enclosing scopes from which you can safely jump 4385e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // into the target scope. 'Min' will end up being the index of 4395e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // the shallowest such scope. 440ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned Min = TargetScope; 441ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall while (true) { 442ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Reachable.set(Min); 443ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 444ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Don't go beyond the outermost scope. 445ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (Min == 0) break; 446ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 4475e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Stop if we can't trivially enter the current scope. 448ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (Scopes[Min].InDiag) break; 4495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 450ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Min = Scopes[Min].ParentScope; 4515af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 4525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 453ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Walk through all the jump sites, checking that they can trivially 454ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // reach this label scope. 455ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (llvm::SmallVectorImpl<JumpScope>::iterator 456ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { 457ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned Scope = I->first; 458ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 459ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Walk out the "scope chain" for this scope, looking for a scope 4605e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // we've marked reachable. For well-formed code this amortizes 4615e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // to O(JumpScopes.size() / Scopes.size()): we only iterate 4625e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // when we see something unmarked, and in well-formed code we 4635e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // mark everything we iterate past. 464ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall bool IsReachable = false; 465ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall while (true) { 466ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (Reachable.test(Scope)) { 467ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // If we find something reachable, mark all the scopes we just 468ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // walked through as reachable. 469ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) 470ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Reachable.set(S); 471ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall IsReachable = true; 472ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall break; 473ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 474ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 475ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Don't walk out if we've reached the top-level scope or we've 476ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // gotten shallower than the shallowest reachable scope. 477ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (Scope == 0 || Scope < Min) break; 478ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 479ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Don't walk out through an out-diagnostic. 480ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (Scopes[Scope].OutDiag) break; 481ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 482ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall Scope = Scopes[Scope].ParentScope; 483ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall } 484ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 485ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Only diagnose if we didn't find something. 486ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (IsReachable) continue; 487ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 488ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); 4895af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 4905af280ce21af061f96b5b5b752746871e364ba99Chris Lattner } 4915af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 4925af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 4935e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall/// Diagnose an indirect jump which is known to cross scopes. 494ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCallvoid JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, 495ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned JumpScope, 496ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall LabelStmt *Target, 497ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall unsigned TargetScope) { 498ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall assert(JumpScope != TargetScope); 499ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 500ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall S.Diag(Jump->getGotoLoc(), diag::warn_indirect_goto_in_protected_scope); 501ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target); 502ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 5035e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); 5045e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall 5055e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Walk out the scope chain until we reach the common ancestor. 5065e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) 5075e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall if (Scopes[I].OutDiag) 5085e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); 509ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 510ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall // Now walk into the scopes containing the label whose address was taken. 5115e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) 5125e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall if (Scopes[I].InDiag) 5135e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall S.Diag(Scopes[I].Loc, Scopes[I].InDiag); 514ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall} 515ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 5165af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// CheckJump - Validate that the specified jump statement is valid: that it is 5175af280ce21af061f96b5b5b752746871e364ba99Chris Lattner/// jumping within or out of its current scope, not into a deeper one. 5185af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, 5195af280ce21af061f96b5b5b752746871e364ba99Chris Lattner SourceLocation DiagLoc, unsigned JumpDiag) { 5205af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); 5215af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned FromScope = LabelAndGotoScopes[From]; 5225af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 5235af280ce21af061f96b5b5b752746871e364ba99Chris Lattner assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); 5245af280ce21af061f96b5b5b752746871e364ba99Chris Lattner unsigned ToScope = LabelAndGotoScopes[To]; 5251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5265af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Common case: exactly the same scope, which is fine. 5275af280ce21af061f96b5b5b752746871e364ba99Chris Lattner if (FromScope == ToScope) return; 5281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5295e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); 5301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5315e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // It's okay to jump out from a nested scope. 5325e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall if (CommonScope == ToScope) return; 5331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5345e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // Pull out (and reverse) any scopes we might need to diagnose skipping. 5355e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall llvm::SmallVector<unsigned, 10> ToScopes; 5365e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) 5375e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall if (Scopes[I].InDiag) 5385e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall ToScopes.push_back(I); 5395e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall 5405e2a7acbdc9e4aee4da54e1e2f560a78bf6fb3c1John McCall // If the only scopes present are cleanup scopes, we're okay. 541ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall if (ToScopes.empty()) return; 542ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 543ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall S.Diag(DiagLoc, JumpDiag); 544ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall 5455af280ce21af061f96b5b5b752746871e364ba99Chris Lattner // Emit diagnostics for whatever is left in ToScopes. 5465af280ce21af061f96b5b5b752746871e364ba99Chris Lattner for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) 547ddb0b4d5391d3e6bc9dcf93dc42310b20c96b6fcJohn McCall S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag); 5485af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 5495af280ce21af061f96b5b5b752746871e364ba99Chris Lattner 5505af280ce21af061f96b5b5b752746871e364ba99Chris Lattnervoid Sema::DiagnoseInvalidJumps(Stmt *Body) { 5516490ae5003226cae28f980648948bea8b21a8638Douglas Gregor (void)JumpScopeChecker(Body, *this); 5525af280ce21af061f96b5b5b752746871e364ba99Chris Lattner} 553