JumpDiagnostics.cpp revision 226633
1200590Sluigi//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// 2200673Sru// 3272840Smelifaro// The LLVM Compiler Infrastructure 4272840Smelifaro// 5200590Sluigi// This file is distributed under the University of Illinois Open Source 6200590Sluigi// License. See LICENSE.TXT for details. 7200590Sluigi// 8200590Sluigi//===----------------------------------------------------------------------===// 9200590Sluigi// 10200590Sluigi// This file implements the JumpScopeChecker class, which is used to diagnose 11200590Sluigi// jumps that enter a protected scope in an invalid way. 12200590Sluigi// 13200590Sluigi//===----------------------------------------------------------------------===// 14200590Sluigi 15200590Sluigi#include "clang/Sema/SemaInternal.h" 16200590Sluigi#include "clang/AST/DeclCXX.h" 17200590Sluigi#include "clang/AST/Expr.h" 18200590Sluigi#include "clang/AST/ExprCXX.h" 19200590Sluigi#include "clang/AST/StmtObjC.h" 20200590Sluigi#include "clang/AST/StmtCXX.h" 21200590Sluigi#include "llvm/ADT/BitVector.h" 22200590Sluigiusing namespace clang; 23200590Sluigi 24200590Sluiginamespace { 25200590Sluigi 26200590Sluigi/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps 27200590Sluigi/// into VLA and other protected scopes. For example, this rejects: 28200590Sluigi/// goto L; 29200590Sluigi/// int a[n]; 30200590Sluigi/// L: 31200590Sluigi/// 32272840Smelifaroclass JumpScopeChecker { 33200601Sluigi Sema &S; 34272840Smelifaro 35272840Smelifaro /// GotoScope - This is a record that we use to keep track of all of the 36200838Sluigi /// scopes that are introduced by VLAs and other things that scope jumps like 37272840Smelifaro /// gotos. This scope tree has nothing to do with the source scope tree, 38272840Smelifaro /// because you can have multiple VLA scopes per compound statement, and most 39272840Smelifaro /// compound statements don't introduce any scopes. 40272840Smelifaro struct GotoScope { 41200590Sluigi /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for 42200590Sluigi /// the parent scope is the function body. 43225518Sjhb unsigned ParentScope; 44200590Sluigi 45200590Sluigi /// InDiag - The diagnostic to emit if there is a jump into this scope. 46200590Sluigi unsigned InDiag; 47200590Sluigi 48200590Sluigi /// OutDiag - The diagnostic to emit if there is an indirect jump out 49200590Sluigi /// of this scope. Direct jumps always clean up their current scope 50200590Sluigi /// in an orderly way. 51272840Smelifaro unsigned OutDiag; 52200590Sluigi 53272840Smelifaro /// Loc - Location to emit the diagnostic. 54240494Sglebius SourceLocation Loc; 55200590Sluigi 56200590Sluigi GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, 57200590Sluigi SourceLocation L) 58201732Sluigi : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} 59200590Sluigi }; 60200590Sluigi 61240494Sglebius SmallVector<GotoScope, 48> Scopes; 62272840Smelifaro llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; 63240494Sglebius SmallVector<Stmt*, 16> Jumps; 64272840Smelifaro 65272840Smelifaro SmallVector<IndirectGotoStmt*, 4> IndirectJumps; 66272840Smelifaro SmallVector<LabelDecl*, 4> IndirectJumpTargets; 67272840Smelifaropublic: 68272840Smelifaro JumpScopeChecker(Stmt *Body, Sema &S); 69272840Smelifaroprivate: 70272840Smelifaro void BuildScopeInformation(Decl *D, unsigned &ParentScope); 71272840Smelifaro void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, 72272840Smelifaro unsigned &ParentScope); 73272840Smelifaro void BuildScopeInformation(Stmt *S, unsigned &origParentScope); 74272840Smelifaro 75272840Smelifaro void VerifyJumps(); 76272840Smelifaro void VerifyIndirectJumps(); 77272840Smelifaro void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, 78272840Smelifaro LabelDecl *Target, unsigned TargetScope); 79272840Smelifaro void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, 80272840Smelifaro unsigned JumpDiag, unsigned JumpDiagWarning); 81272840Smelifaro 82272840Smelifaro unsigned GetDeepestCommonScope(unsigned A, unsigned B); 83272840Smelifaro}; 84272840Smelifaro} // end anonymous namespace 85272840Smelifaro 86272840Smelifaro 87272840SmelifaroJumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { 88272840Smelifaro // Add a scope entry for function scope. 89272840Smelifaro Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); 90272840Smelifaro 91200590Sluigi // Build information for the top level compound statement, so that we have a 92282070Smelifaro // defined scope record for every "goto" and label. 93282070Smelifaro unsigned BodyParentScope = 0; 94272840Smelifaro BuildScopeInformation(Body, BodyParentScope); 95272840Smelifaro 96272840Smelifaro // Check that all jumps we saw are kosher. 97272840Smelifaro VerifyJumps(); 98272840Smelifaro VerifyIndirectJumps(); 99272840Smelifaro} 100272840Smelifaro 101272840Smelifaro/// GetDeepestCommonScope - Finds the innermost scope enclosing the 102272840Smelifaro/// two scopes. 103272840Smelifarounsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { 104272840Smelifaro while (A != B) { 105272840Smelifaro // Inner scopes are created after outer scopes and therefore have 106272840Smelifaro // higher indices. 107272840Smelifaro if (A < B) { 108272840Smelifaro assert(Scopes[B].ParentScope < B); 109272840Smelifaro B = Scopes[B].ParentScope; 110272840Smelifaro } else { 111272840Smelifaro assert(Scopes[A].ParentScope < A); 112272840Smelifaro A = Scopes[A].ParentScope; 113272840Smelifaro } 114200590Sluigi } 115272840Smelifaro return A; 116272840Smelifaro} 117200590Sluigi 118290332Saetypedef std::pair<unsigned,unsigned> ScopePair; 119272840Smelifaro 120272840Smelifaro/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a 121272840Smelifaro/// diagnostic that should be emitted if control goes over it. If not, return 0. 122232865Smelifarostatic ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { 123272840Smelifaro if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { 124272840Smelifaro unsigned InDiag = 0, OutDiag = 0; 125232865Smelifaro if (VD->getType()->isVariablyModifiedType()) 126272840Smelifaro InDiag = diag::note_protected_by_vla; 127272840Smelifaro 128272840Smelifaro if (VD->hasAttr<BlocksAttr>()) 129272840Smelifaro return ScopePair(diag::note_protected_by___block, 130272840Smelifaro diag::note_exits___block); 131272840Smelifaro 132272840Smelifaro if (VD->hasAttr<CleanupAttr>()) 133272840Smelifaro return ScopePair(diag::note_protected_by_cleanup, 134272840Smelifaro diag::note_exits_cleanup); 135272840Smelifaro 136272840Smelifaro if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) { 137272840Smelifaro switch (VD->getType().getObjCLifetime()) { 138272840Smelifaro case Qualifiers::OCL_None: 139272840Smelifaro case Qualifiers::OCL_ExplicitNone: 140272840Smelifaro case Qualifiers::OCL_Autoreleasing: 141272840Smelifaro break; 142272840Smelifaro 143272840Smelifaro case Qualifiers::OCL_Strong: 144272840Smelifaro case Qualifiers::OCL_Weak: 145272840Smelifaro return ScopePair(diag::note_protected_by_objc_ownership, 146272840Smelifaro diag::note_exits_objc_ownership); 147272840Smelifaro } 148272840Smelifaro } 149272840Smelifaro 150272840Smelifaro if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) { 151272840Smelifaro // C++0x [stmt.dcl]p3: 152272840Smelifaro // A program that jumps from a point where a variable with automatic 153272840Smelifaro // storage duration is not in scope to a point where it is in scope 154272840Smelifaro // is ill-formed unless the variable has scalar type, class type with 155272840Smelifaro // a trivial default constructor and a trivial destructor, a 156272840Smelifaro // cv-qualified version of one of these types, or an array of one of 157272840Smelifaro // the preceding types and is declared without an initializer. 158272840Smelifaro 159272840Smelifaro // C++03 [stmt.dcl.p3: 160272840Smelifaro // A program that jumps from a point where a local variable 161272840Smelifaro // with automatic storage duration is not in scope to a point 162272840Smelifaro // where it is in scope is ill-formed unless the variable has 163272840Smelifaro // POD type and is declared without an initializer. 164272840Smelifaro 165272840Smelifaro if (const Expr *init = VD->getInit()) { 166272840Smelifaro // We actually give variables of record type (or array thereof) 167272840Smelifaro // an initializer even if that initializer only calls a trivial 168272840Smelifaro // ctor. Detect that case. 169272840Smelifaro // FIXME: With generalized initializer lists, this may 170272840Smelifaro // classify "X x{};" as having no initializer. 171272840Smelifaro unsigned inDiagToUse = diag::note_protected_by_variable_init; 172272840Smelifaro 173272840Smelifaro const CXXRecordDecl *record = 0; 174272840Smelifaro 175272840Smelifaro if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) { 176272840Smelifaro const CXXConstructorDecl *ctor = cce->getConstructor(); 177272840Smelifaro record = ctor->getParent(); 178272840Smelifaro 179272840Smelifaro if (ctor->isTrivial() && ctor->isDefaultConstructor()) { 180272840Smelifaro if (Context.getLangOptions().CPlusPlus0x) { 181272840Smelifaro inDiagToUse = (record->hasTrivialDestructor() ? 0 : 182272840Smelifaro diag::note_protected_by_variable_nontriv_destructor); 183272840Smelifaro } else { 184272840Smelifaro if (record->isPOD()) 185272840Smelifaro inDiagToUse = 0; 186272840Smelifaro } 187272840Smelifaro } 188201120Sluigi } else if (VD->getType()->isArrayType()) { 189272840Smelifaro record = VD->getType()->getBaseElementTypeUnsafe() 190272840Smelifaro ->getAsCXXRecordDecl(); 191272840Smelifaro } 192272840Smelifaro 193272840Smelifaro if (inDiagToUse) 194272840Smelifaro InDiag = inDiagToUse; 195201120Sluigi 196272840Smelifaro // Also object to indirect jumps which leave scopes with dtors. 197272840Smelifaro if (record && !record->hasTrivialDestructor()) 198272840Smelifaro OutDiag = diag::note_exits_dtor; 199272840Smelifaro } 200272840Smelifaro } 201272840Smelifaro 202272840Smelifaro return ScopePair(InDiag, OutDiag); 203272840Smelifaro } 204272840Smelifaro 205272840Smelifaro if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { 206272840Smelifaro if (TD->getUnderlyingType()->isVariablyModifiedType()) 207272840Smelifaro return ScopePair(diag::note_protected_by_vla_typedef, 0); 208272840Smelifaro } 209272840Smelifaro 210272840Smelifaro if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { 211272840Smelifaro if (TD->getUnderlyingType()->isVariablyModifiedType()) 212272840Smelifaro return ScopePair(diag::note_protected_by_vla_type_alias, 0); 213272840Smelifaro } 214272840Smelifaro 215272840Smelifaro return ScopePair(0U, 0U); 216272840Smelifaro} 217272840Smelifaro 218272840Smelifaro/// \brief Build scope information for a declaration that is part of a DeclStmt. 219272840Smelifarovoid JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { 220232865Smelifaro // If this decl causes a new scope, push and switch to it. 221272840Smelifaro std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D); 222272840Smelifaro if (Diags.first || Diags.second) { 223232865Smelifaro Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, 224272840Smelifaro D->getLocation())); 225272840Smelifaro ParentScope = Scopes.size()-1; 226272840Smelifaro } 227272840Smelifaro 228201120Sluigi // If the decl has an initializer, walk it with the potentially new 229272840Smelifaro // scope we just installed. 230232865Smelifaro if (VarDecl *VD = dyn_cast<VarDecl>(D)) 231272840Smelifaro if (Expr *Init = VD->getInit()) 232272840Smelifaro BuildScopeInformation(Init, ParentScope); 233272840Smelifaro} 234272840Smelifaro 235272840Smelifaro/// \brief Build scope information for a captured block literal variables. 236272840Smelifarovoid JumpScopeChecker::BuildScopeInformation(VarDecl *D, 237272840Smelifaro const BlockDecl *BDecl, 238272840Smelifaro unsigned &ParentScope) { 239272840Smelifaro // exclude captured __block variables; there's no destructor 240272840Smelifaro // associated with the block literal for them. 241272840Smelifaro if (D->hasAttr<BlocksAttr>()) 242272840Smelifaro return; 243272840Smelifaro QualType T = D->getType(); 244272840Smelifaro QualType::DestructionKind destructKind = T.isDestructedType(); 245272840Smelifaro if (destructKind != QualType::DK_none) { 246272840Smelifaro std::pair<unsigned,unsigned> Diags; 247232865Smelifaro switch (destructKind) { 248272840Smelifaro case QualType::DK_cxx_destructor: 249272840Smelifaro Diags = ScopePair(diag::note_enters_block_captures_cxx_obj, 250272840Smelifaro diag::note_exits_block_captures_cxx_obj); 251272840Smelifaro break; 252272840Smelifaro case QualType::DK_objc_strong_lifetime: 253272840Smelifaro Diags = ScopePair(diag::note_enters_block_captures_strong, 254272840Smelifaro diag::note_exits_block_captures_strong); 255272840Smelifaro break; 256272840Smelifaro case QualType::DK_objc_weak_lifetime: 257272840Smelifaro Diags = ScopePair(diag::note_enters_block_captures_weak, 258272840Smelifaro diag::note_exits_block_captures_weak); 259272840Smelifaro break; 260272840Smelifaro case QualType::DK_none: 261272840Smelifaro llvm_unreachable("no-liftime captured variable"); 262232865Smelifaro } 263272840Smelifaro SourceLocation Loc = D->getLocation(); 264272840Smelifaro if (Loc.isInvalid()) 265232865Smelifaro Loc = BDecl->getLocation(); 266272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 267272840Smelifaro Diags.first, Diags.second, Loc)); 268272840Smelifaro ParentScope = Scopes.size()-1; 269272840Smelifaro } 270272840Smelifaro} 271272840Smelifaro 272272840Smelifaro/// BuildScopeInformation - The statements from CI to CE are known to form a 273272840Smelifaro/// coherent VLA scope with a specified parent node. Walk through the 274272840Smelifaro/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively 275232865Smelifaro/// walking the AST as needed. 276232865Smelifarovoid JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) { 277272840Smelifaro // If this is a statement, rather than an expression, scopes within it don't 278272840Smelifaro // propagate out into the enclosing scope. Otherwise we have to worry 279272840Smelifaro // about block literals, which have the lifetime of their enclosing statement. 280272840Smelifaro unsigned independentParentScope = origParentScope; 281272840Smelifaro unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S)) 282272840Smelifaro ? origParentScope : independentParentScope); 283272840Smelifaro 284272840Smelifaro bool SkipFirstSubStmt = false; 285272840Smelifaro 286272840Smelifaro // If we found a label, remember that it is in ParentScope scope. 287272840Smelifaro switch (S->getStmtClass()) { 288272840Smelifaro case Stmt::AddrLabelExprClass: 289272840Smelifaro IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); 290200590Sluigi break; 291272840Smelifaro 292272840Smelifaro case Stmt::IndirectGotoStmtClass: 293272840Smelifaro // "goto *&&lbl;" is a special case which we treat as equivalent 294272840Smelifaro // to a normal goto. In addition, we don't calculate scope in the 295200590Sluigi // operand (to avoid recording the address-of-label use), which 296272840Smelifaro // works only because of the restricted set of expressions which 297232865Smelifaro // we detect as constant targets. 298272840Smelifaro if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { 299272840Smelifaro LabelAndGotoScopes[S] = ParentScope; 300272840Smelifaro Jumps.push_back(S); 301272840Smelifaro return; 302282070Smelifaro } 303232865Smelifaro 304272840Smelifaro LabelAndGotoScopes[S] = ParentScope; 305272840Smelifaro IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); 306272840Smelifaro break; 307272840Smelifaro 308272840Smelifaro case Stmt::SwitchStmtClass: 309272840Smelifaro // Evaluate the condition variable before entering the scope of the switch 310272840Smelifaro // statement. 311272840Smelifaro if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { 312272840Smelifaro BuildScopeInformation(Var, ParentScope); 313272840Smelifaro SkipFirstSubStmt = true; 314272840Smelifaro } 315272840Smelifaro // Fall through 316272840Smelifaro 317272840Smelifaro case Stmt::GotoStmtClass: 318272840Smelifaro // Remember both what scope a goto is in as well as the fact that we have 319272840Smelifaro // it. This makes the second scan not have to walk the AST again. 320272840Smelifaro LabelAndGotoScopes[S] = ParentScope; 321272840Smelifaro Jumps.push_back(S); 322272840Smelifaro break; 323272840Smelifaro 324272840Smelifaro default: 325272840Smelifaro break; 326272840Smelifaro } 327272840Smelifaro 328272840Smelifaro for (Stmt::child_range CI = S->children(); CI; ++CI) { 329272840Smelifaro if (SkipFirstSubStmt) { 330272840Smelifaro SkipFirstSubStmt = false; 331272840Smelifaro continue; 332272840Smelifaro } 333272840Smelifaro 334272840Smelifaro Stmt *SubStmt = *CI; 335272840Smelifaro if (SubStmt == 0) continue; 336272840Smelifaro 337272840Smelifaro // Cases, labels, and defaults aren't "scope parents". It's also 338272840Smelifaro // important to handle these iteratively instead of recursively in 339272840Smelifaro // order to avoid blowing out the stack. 340272840Smelifaro while (true) { 341272840Smelifaro Stmt *Next; 342272840Smelifaro if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt)) 343272840Smelifaro Next = CS->getSubStmt(); 344272840Smelifaro else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt)) 345272840Smelifaro Next = DS->getSubStmt(); 346272840Smelifaro else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) 347272840Smelifaro Next = LS->getSubStmt(); 348272840Smelifaro else 349272840Smelifaro break; 350272840Smelifaro 351272840Smelifaro LabelAndGotoScopes[SubStmt] = ParentScope; 352272840Smelifaro SubStmt = Next; 353272840Smelifaro } 354272840Smelifaro 355272840Smelifaro // If this is a declstmt with a VLA definition, it defines a scope from here 356272840Smelifaro // to the end of the containing context. 357272840Smelifaro if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { 358272840Smelifaro // The decl statement creates a scope if any of the decls in it are VLAs 359272840Smelifaro // or have the cleanup attribute. 360272840Smelifaro for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 361272840Smelifaro I != E; ++I) 362272840Smelifaro BuildScopeInformation(*I, ParentScope); 363272840Smelifaro continue; 364272840Smelifaro } 365272840Smelifaro // Disallow jumps into any part of an @try statement by pushing a scope and 366272840Smelifaro // walking all sub-stmts in that scope. 367272840Smelifaro if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { 368272840Smelifaro unsigned newParentScope; 369272840Smelifaro // Recursively walk the AST for the @try part. 370272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 371272840Smelifaro diag::note_protected_by_objc_try, 372272840Smelifaro diag::note_exits_objc_try, 373272840Smelifaro AT->getAtTryLoc())); 374272840Smelifaro if (Stmt *TryPart = AT->getTryBody()) 375272840Smelifaro BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1)); 376272840Smelifaro 377272840Smelifaro // Jump from the catch to the finally or try is not valid. 378272840Smelifaro for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { 379232865Smelifaro ObjCAtCatchStmt *AC = AT->getCatchStmt(I); 380272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 381272840Smelifaro diag::note_protected_by_objc_catch, 382272840Smelifaro diag::note_exits_objc_catch, 383272840Smelifaro AC->getAtCatchLoc())); 384272840Smelifaro // @catches are nested and it isn't 385272840Smelifaro BuildScopeInformation(AC->getCatchBody(), 386272840Smelifaro (newParentScope = Scopes.size()-1)); 387272840Smelifaro } 388272840Smelifaro 389272840Smelifaro // Jump from the finally to the try or catch is not valid. 390272840Smelifaro if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { 391272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 392272840Smelifaro diag::note_protected_by_objc_finally, 393272840Smelifaro diag::note_exits_objc_finally, 394272840Smelifaro AF->getAtFinallyLoc())); 395272840Smelifaro BuildScopeInformation(AF, (newParentScope = Scopes.size()-1)); 396272840Smelifaro } 397272840Smelifaro 398272840Smelifaro continue; 399272840Smelifaro } 400272840Smelifaro 401272840Smelifaro unsigned newParentScope; 402272840Smelifaro // Disallow jumps into the protected statement of an @synchronized, but 403272840Smelifaro // allow jumps into the object expression it protects. 404272840Smelifaro if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ 405272840Smelifaro // Recursively walk the AST for the @synchronized object expr, it is 406272840Smelifaro // evaluated in the normal scope. 407272840Smelifaro BuildScopeInformation(AS->getSynchExpr(), ParentScope); 408272840Smelifaro 409272840Smelifaro // Recursively walk the AST for the @synchronized part, protected by a new 410272840Smelifaro // scope. 411272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 412272840Smelifaro diag::note_protected_by_objc_synchronized, 413272840Smelifaro diag::note_exits_objc_synchronized, 414272840Smelifaro AS->getAtSynchronizedLoc())); 415272840Smelifaro BuildScopeInformation(AS->getSynchBody(), 416272840Smelifaro (newParentScope = Scopes.size()-1)); 417272840Smelifaro continue; 418272840Smelifaro } 419272840Smelifaro 420272840Smelifaro // Disallow jumps into any part of a C++ try statement. This is pretty 421272840Smelifaro // much the same as for Obj-C. 422272840Smelifaro if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { 423272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 424272840Smelifaro diag::note_protected_by_cxx_try, 425272840Smelifaro diag::note_exits_cxx_try, 426272840Smelifaro TS->getSourceRange().getBegin())); 427272840Smelifaro if (Stmt *TryBlock = TS->getTryBlock()) 428272840Smelifaro BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); 429272840Smelifaro 430272840Smelifaro // Jump from the catch into the try is not allowed either. 431272840Smelifaro for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { 432272840Smelifaro CXXCatchStmt *CS = TS->getHandler(I); 433272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 434272840Smelifaro diag::note_protected_by_cxx_catch, 435272840Smelifaro diag::note_exits_cxx_catch, 436272840Smelifaro CS->getSourceRange().getBegin())); 437272840Smelifaro BuildScopeInformation(CS->getHandlerBlock(), 438272840Smelifaro (newParentScope = Scopes.size()-1)); 439272840Smelifaro } 440272840Smelifaro 441272840Smelifaro continue; 442272840Smelifaro } 443272840Smelifaro 444272840Smelifaro // Disallow jumps into the protected statement of an @autoreleasepool. 445272840Smelifaro if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){ 446272840Smelifaro // Recursively walk the AST for the @autoreleasepool part, protected by a new 447272840Smelifaro // scope. 448272840Smelifaro Scopes.push_back(GotoScope(ParentScope, 449272840Smelifaro diag::note_protected_by_objc_autoreleasepool, 450272840Smelifaro diag::note_exits_objc_autoreleasepool, 451272840Smelifaro AS->getAtLoc())); 452272840Smelifaro BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1)); 453272840Smelifaro continue; 454272840Smelifaro } 455272840Smelifaro 456272840Smelifaro if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) { 457272840Smelifaro const BlockDecl *BDecl = BE->getBlockDecl(); 458272840Smelifaro for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(), 459272840Smelifaro ce = BDecl->capture_end(); ci != ce; ++ci) { 460272840Smelifaro VarDecl *variable = ci->getVariable(); 461272840Smelifaro BuildScopeInformation(variable, BDecl, ParentScope); 462272840Smelifaro } 463272840Smelifaro } 464272840Smelifaro 465272840Smelifaro // Recursively walk the AST. 466272840Smelifaro BuildScopeInformation(SubStmt, ParentScope); 467272840Smelifaro } 468272840Smelifaro} 469272840Smelifaro 470272840Smelifaro/// VerifyJumps - Verify each element of the Jumps array to see if they are 471272840Smelifaro/// valid, emitting diagnostics if not. 472272840Smelifarovoid JumpScopeChecker::VerifyJumps() { 473272840Smelifaro while (!Jumps.empty()) { 474272840Smelifaro Stmt *Jump = Jumps.pop_back_val(); 475272840Smelifaro 476272840Smelifaro // With a goto, 477272840Smelifaro if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { 478272840Smelifaro CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), 479272840Smelifaro diag::err_goto_into_protected_scope, 480272840Smelifaro diag::warn_goto_into_protected_scope); 481272840Smelifaro continue; 482272840Smelifaro } 483272840Smelifaro 484272840Smelifaro // We only get indirect gotos here when they have a constant target. 485272840Smelifaro if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { 486272840Smelifaro LabelDecl *Target = IGS->getConstantTarget(); 487272840Smelifaro CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), 488272840Smelifaro diag::err_goto_into_protected_scope, 489272840Smelifaro diag::warn_goto_into_protected_scope); 490272840Smelifaro continue; 491272840Smelifaro } 492272840Smelifaro 493272840Smelifaro SwitchStmt *SS = cast<SwitchStmt>(Jump); 494272840Smelifaro for (SwitchCase *SC = SS->getSwitchCaseList(); SC; 495272840Smelifaro SC = SC->getNextSwitchCase()) { 496272840Smelifaro assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); 497272840Smelifaro CheckJump(SS, SC, SC->getLocStart(), 498272840Smelifaro diag::err_switch_into_protected_scope, 0); 499272840Smelifaro } 500272840Smelifaro } 501272840Smelifaro} 502272840Smelifaro 503272840Smelifaro/// VerifyIndirectJumps - Verify whether any possible indirect jump 504272840Smelifaro/// might cross a protection boundary. Unlike direct jumps, indirect 505272840Smelifaro/// jumps count cleanups as protection boundaries: since there's no 506272840Smelifaro/// way to know where the jump is going, we can't implicitly run the 507272840Smelifaro/// right cleanups the way we can with direct jumps. 508272840Smelifaro/// 509272840Smelifaro/// Thus, an indirect jump is "trivial" if it bypasses no 510272840Smelifaro/// initializations and no teardowns. More formally, an indirect jump 511272840Smelifaro/// from A to B is trivial if the path out from A to DCA(A,B) is 512272840Smelifaro/// trivial and the path in from DCA(A,B) to B is trivial, where 513272840Smelifaro/// DCA(A,B) is the deepest common ancestor of A and B. 514272840Smelifaro/// Jump-triviality is transitive but asymmetric. 515272840Smelifaro/// 516272840Smelifaro/// A path in is trivial if none of the entered scopes have an InDiag. 517272840Smelifaro/// A path out is trivial is none of the exited scopes have an OutDiag. 518272840Smelifaro/// 519272840Smelifaro/// Under these definitions, this function checks that the indirect 520272840Smelifaro/// jump between A and B is trivial for every indirect goto statement A 521272840Smelifaro/// and every label B whose address was taken in the function. 522272840Smelifarovoid JumpScopeChecker::VerifyIndirectJumps() { 523272840Smelifaro if (IndirectJumps.empty()) return; 524272840Smelifaro 525272840Smelifaro // If there aren't any address-of-label expressions in this function, 526272840Smelifaro // complain about the first indirect goto. 527272840Smelifaro if (IndirectJumpTargets.empty()) { 528272840Smelifaro S.Diag(IndirectJumps[0]->getGotoLoc(), 529272840Smelifaro diag::err_indirect_goto_without_addrlabel); 530272840Smelifaro return; 531272840Smelifaro } 532272840Smelifaro 533272840Smelifaro // Collect a single representative of every scope containing an 534272840Smelifaro // indirect goto. For most code bases, this substantially cuts 535272840Smelifaro // down on the number of jump sites we'll have to consider later. 536272840Smelifaro typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; 537272840Smelifaro SmallVector<JumpScope, 32> JumpScopes; 538272840Smelifaro { 539272840Smelifaro llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; 540272840Smelifaro for (SmallVectorImpl<IndirectGotoStmt*>::iterator 541272840Smelifaro I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { 542272840Smelifaro IndirectGotoStmt *IG = *I; 543272840Smelifaro assert(LabelAndGotoScopes.count(IG) && 544272840Smelifaro "indirect jump didn't get added to scopes?"); 545272840Smelifaro unsigned IGScope = LabelAndGotoScopes[IG]; 546272840Smelifaro IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; 547272840Smelifaro if (!Entry) Entry = IG; 548272840Smelifaro } 549272840Smelifaro JumpScopes.reserve(JumpScopesMap.size()); 550272840Smelifaro for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator 551272840Smelifaro I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) 552272840Smelifaro JumpScopes.push_back(*I); 553272840Smelifaro } 554272840Smelifaro 555272840Smelifaro // Collect a single representative of every scope containing a 556272840Smelifaro // label whose address was taken somewhere in the function. 557272840Smelifaro // For most code bases, there will be only one such scope. 558272840Smelifaro llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; 559272840Smelifaro for (SmallVectorImpl<LabelDecl*>::iterator 560272840Smelifaro I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); 561272840Smelifaro I != E; ++I) { 562272840Smelifaro LabelDecl *TheLabel = *I; 563272840Smelifaro assert(LabelAndGotoScopes.count(TheLabel->getStmt()) && 564272840Smelifaro "Referenced label didn't get added to scopes?"); 565272840Smelifaro unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; 566272840Smelifaro LabelDecl *&Target = TargetScopes[LabelScope]; 567272840Smelifaro if (!Target) Target = TheLabel; 568272840Smelifaro } 569272840Smelifaro 570272840Smelifaro // For each target scope, make sure it's trivially reachable from 571272840Smelifaro // every scope containing a jump site. 572272840Smelifaro // 573272840Smelifaro // A path between scopes always consists of exitting zero or more 574272840Smelifaro // scopes, then entering zero or more scopes. We build a set of 575272840Smelifaro // of scopes S from which the target scope can be trivially 576272840Smelifaro // entered, then verify that every jump scope can be trivially 577272840Smelifaro // exitted to reach a scope in S. 578272840Smelifaro llvm::BitVector Reachable(Scopes.size(), false); 579272840Smelifaro for (llvm::DenseMap<unsigned,LabelDecl*>::iterator 580272840Smelifaro TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { 581272840Smelifaro unsigned TargetScope = TI->first; 582272840Smelifaro LabelDecl *TargetLabel = TI->second; 583272840Smelifaro 584272840Smelifaro Reachable.reset(); 585272840Smelifaro 586272840Smelifaro // Mark all the enclosing scopes from which you can safely jump 587272840Smelifaro // into the target scope. 'Min' will end up being the index of 588272840Smelifaro // the shallowest such scope. 589272840Smelifaro unsigned Min = TargetScope; 590272840Smelifaro while (true) { 591272840Smelifaro Reachable.set(Min); 592272840Smelifaro 593272840Smelifaro // Don't go beyond the outermost scope. 594272840Smelifaro if (Min == 0) break; 595272840Smelifaro 596272840Smelifaro // Stop if we can't trivially enter the current scope. 597272840Smelifaro if (Scopes[Min].InDiag) break; 598272840Smelifaro 599272840Smelifaro Min = Scopes[Min].ParentScope; 600272840Smelifaro } 601272840Smelifaro 602272840Smelifaro // Walk through all the jump sites, checking that they can trivially 603282521Smelifaro // reach this label scope. 604272840Smelifaro for (SmallVectorImpl<JumpScope>::iterator 605272840Smelifaro I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { 606272840Smelifaro unsigned Scope = I->first; 607282521Smelifaro 608282521Smelifaro // Walk out the "scope chain" for this scope, looking for a scope 609282521Smelifaro // we've marked reachable. For well-formed code this amortizes 610282521Smelifaro // to O(JumpScopes.size() / Scopes.size()): we only iterate 611272840Smelifaro // when we see something unmarked, and in well-formed code we 612272840Smelifaro // mark everything we iterate past. 613272840Smelifaro bool IsReachable = false; 614272840Smelifaro while (true) { 615272840Smelifaro if (Reachable.test(Scope)) { 616272840Smelifaro // If we find something reachable, mark all the scopes we just 617272840Smelifaro // walked through as reachable. 618272840Smelifaro for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) 619272840Smelifaro Reachable.set(S); 620272840Smelifaro IsReachable = true; 621272840Smelifaro break; 622272840Smelifaro } 623272840Smelifaro 624272840Smelifaro // Don't walk out if we've reached the top-level scope or we've 625272840Smelifaro // gotten shallower than the shallowest reachable scope. 626272840Smelifaro if (Scope == 0 || Scope < Min) break; 627272840Smelifaro 628272840Smelifaro // Don't walk out through an out-diagnostic. 629272840Smelifaro if (Scopes[Scope].OutDiag) break; 630272840Smelifaro 631272840Smelifaro Scope = Scopes[Scope].ParentScope; 632272840Smelifaro } 633272840Smelifaro 634272840Smelifaro // Only diagnose if we didn't find something. 635272840Smelifaro if (IsReachable) continue; 636272840Smelifaro 637272840Smelifaro DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); 638272840Smelifaro } 639272840Smelifaro } 640272840Smelifaro} 641272840Smelifaro 642272840Smelifaro/// Diagnose an indirect jump which is known to cross scopes. 643272840Smelifarovoid JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, 644272840Smelifaro unsigned JumpScope, 645272840Smelifaro LabelDecl *Target, 646272840Smelifaro unsigned TargetScope) { 647272840Smelifaro assert(JumpScope != TargetScope); 648272840Smelifaro 649272840Smelifaro S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); 650272840Smelifaro S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); 651272840Smelifaro 652272840Smelifaro unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); 653272840Smelifaro 654272840Smelifaro // Walk out the scope chain until we reach the common ancestor. 655272840Smelifaro for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) 656272840Smelifaro if (Scopes[I].OutDiag) 657272840Smelifaro S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); 658272840Smelifaro 659272840Smelifaro // Now walk into the scopes containing the label whose address was taken. 660272840Smelifaro for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) 661272840Smelifaro if (Scopes[I].InDiag) 662272840Smelifaro S.Diag(Scopes[I].Loc, Scopes[I].InDiag); 663272840Smelifaro} 664272840Smelifaro 665272840Smelifaro/// Return true if a particular error+note combination must be downgraded 666272840Smelifaro/// to a warning in Microsoft mode. 667272840Smelifarostatic bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) 668272840Smelifaro{ 669272840Smelifaro return (JumpDiag == diag::err_goto_into_protected_scope && 670272840Smelifaro (InDiagNote == diag::note_protected_by_variable_init || 671272840Smelifaro InDiagNote == diag::note_protected_by_variable_nontriv_destructor)); 672272840Smelifaro} 673272840Smelifaro 674272840Smelifaro 675272840Smelifaro/// CheckJump - Validate that the specified jump statement is valid: that it is 676272840Smelifaro/// jumping within or out of its current scope, not into a deeper one. 677272840Smelifarovoid JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, 678272840Smelifaro unsigned JumpDiagError, unsigned JumpDiagWarning) { 679272840Smelifaro assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); 680272840Smelifaro unsigned FromScope = LabelAndGotoScopes[From]; 681272840Smelifaro 682232865Smelifaro assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); 683272840Smelifaro unsigned ToScope = LabelAndGotoScopes[To]; 684272840Smelifaro 685272840Smelifaro // Common case: exactly the same scope, which is fine. 686272840Smelifaro if (FromScope == ToScope) return; 687272840Smelifaro 688272840Smelifaro unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); 689272840Smelifaro 690272840Smelifaro // It's okay to jump out from a nested scope. 691272840Smelifaro if (CommonScope == ToScope) return; 692272840Smelifaro 693272840Smelifaro // Pull out (and reverse) any scopes we might need to diagnose skipping. 694272840Smelifaro SmallVector<unsigned, 10> ToScopesError; 695272840Smelifaro SmallVector<unsigned, 10> ToScopesWarning; 696272840Smelifaro for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { 697272840Smelifaro if (S.getLangOptions().MicrosoftMode && JumpDiagWarning != 0 && 698272840Smelifaro IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) 699272840Smelifaro ToScopesWarning.push_back(I); 700232865Smelifaro else if (Scopes[I].InDiag) 701272840Smelifaro ToScopesError.push_back(I); 702272840Smelifaro } 703232865Smelifaro 704272840Smelifaro // Handle warnings. 705272840Smelifaro if (!ToScopesWarning.empty()) { 706272840Smelifaro S.Diag(DiagLoc, JumpDiagWarning); 707272840Smelifaro for (unsigned i = 0, e = ToScopesWarning.size(); i != e; ++i) 708272840Smelifaro S.Diag(Scopes[ToScopesWarning[i]].Loc, Scopes[ToScopesWarning[i]].InDiag); 709272840Smelifaro } 710272840Smelifaro 711272840Smelifaro // Handle errors. 712272840Smelifaro if (!ToScopesError.empty()) { 713272840Smelifaro S.Diag(DiagLoc, JumpDiagError); 714272840Smelifaro // Emit diagnostics note for whatever is left in ToScopesError. 715272840Smelifaro for (unsigned i = 0, e = ToScopesError.size(); i != e; ++i) 716272840Smelifaro S.Diag(Scopes[ToScopesError[i]].Loc, Scopes[ToScopesError[i]].InDiag); 717272840Smelifaro } 718272840Smelifaro} 719272840Smelifaro 720272840Smelifarovoid Sema::DiagnoseInvalidJumps(Stmt *Body) { 721232865Smelifaro (void)JumpScopeChecker(Body, *this); 722272840Smelifaro} 723272840Smelifaro