1226633Sdim//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// 2193326Sed// 3193326Sed// The LLVM Compiler Infrastructure 4193326Sed// 5193326Sed// This file is distributed under the University of Illinois Open Source 6193326Sed// License. See LICENSE.TXT for details. 7193326Sed// 8193326Sed//===----------------------------------------------------------------------===// 9193326Sed// 10193326Sed// This file implements the JumpScopeChecker class, which is used to diagnose 11226633Sdim// jumps that enter a protected scope in an invalid way. 12193326Sed// 13193326Sed//===----------------------------------------------------------------------===// 14193326Sed 15212904Sdim#include "clang/Sema/SemaInternal.h" 16212904Sdim#include "clang/AST/DeclCXX.h" 17193326Sed#include "clang/AST/Expr.h" 18223017Sdim#include "clang/AST/ExprCXX.h" 19249423Sdim#include "clang/AST/StmtCXX.h" 20193326Sed#include "clang/AST/StmtObjC.h" 21212904Sdim#include "llvm/ADT/BitVector.h" 22193326Sedusing namespace clang; 23193326Sed 24193326Sednamespace { 25193326Sed 26193326Sed/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps 27193326Sed/// into VLA and other protected scopes. For example, this rejects: 28193326Sed/// goto L; 29193326Sed/// int a[n]; 30193326Sed/// L: 31193326Sed/// 32193326Sedclass JumpScopeChecker { 33193326Sed Sema &S; 34198092Srdivacky 35193326Sed /// GotoScope - This is a record that we use to keep track of all of the 36193326Sed /// scopes that are introduced by VLAs and other things that scope jumps like 37193326Sed /// gotos. This scope tree has nothing to do with the source scope tree, 38193326Sed /// because you can have multiple VLA scopes per compound statement, and most 39193326Sed /// compound statements don't introduce any scopes. 40193326Sed struct GotoScope { 41193326Sed /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for 42193326Sed /// the parent scope is the function body. 43193326Sed unsigned ParentScope; 44198092Srdivacky 45234353Sdim /// InDiag - The note to emit if there is a jump into this scope. 46208600Srdivacky unsigned InDiag; 47198092Srdivacky 48234353Sdim /// OutDiag - The note to emit if there is an indirect jump out 49208600Srdivacky /// of this scope. Direct jumps always clean up their current scope 50208600Srdivacky /// in an orderly way. 51208600Srdivacky unsigned OutDiag; 52208600Srdivacky 53193326Sed /// Loc - Location to emit the diagnostic. 54193326Sed SourceLocation Loc; 55198092Srdivacky 56208600Srdivacky GotoScope(unsigned parentScope, unsigned InDiag, unsigned OutDiag, 57208600Srdivacky SourceLocation L) 58208600Srdivacky : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} 59193326Sed }; 60198092Srdivacky 61226633Sdim SmallVector<GotoScope, 48> Scopes; 62193326Sed llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; 63226633Sdim SmallVector<Stmt*, 16> Jumps; 64208600Srdivacky 65226633Sdim SmallVector<IndirectGotoStmt*, 4> IndirectJumps; 66226633Sdim SmallVector<LabelDecl*, 4> IndirectJumpTargets; 67193326Sedpublic: 68193326Sed JumpScopeChecker(Stmt *Body, Sema &S); 69193326Sedprivate: 70210299Sed void BuildScopeInformation(Decl *D, unsigned &ParentScope); 71224145Sdim void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, 72224145Sdim unsigned &ParentScope); 73224145Sdim void BuildScopeInformation(Stmt *S, unsigned &origParentScope); 74224145Sdim 75193326Sed void VerifyJumps(); 76208600Srdivacky void VerifyIndirectJumps(); 77234353Sdim void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes); 78208600Srdivacky void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, 79218893Sdim LabelDecl *Target, unsigned TargetScope); 80226633Sdim void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, 81234353Sdim unsigned JumpDiag, unsigned JumpDiagWarning, 82234353Sdim unsigned JumpDiagCXX98Compat); 83208600Srdivacky 84208600Srdivacky unsigned GetDeepestCommonScope(unsigned A, unsigned B); 85193326Sed}; 86193326Sed} // end anonymous namespace 87193326Sed 88193326Sed 89193326SedJumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { 90193326Sed // Add a scope entry for function scope. 91208600Srdivacky Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation())); 92198092Srdivacky 93193326Sed // Build information for the top level compound statement, so that we have a 94193326Sed // defined scope record for every "goto" and label. 95224145Sdim unsigned BodyParentScope = 0; 96224145Sdim BuildScopeInformation(Body, BodyParentScope); 97198092Srdivacky 98193326Sed // Check that all jumps we saw are kosher. 99193326Sed VerifyJumps(); 100208600Srdivacky VerifyIndirectJumps(); 101193326Sed} 102198092Srdivacky 103208600Srdivacky/// GetDeepestCommonScope - Finds the innermost scope enclosing the 104208600Srdivacky/// two scopes. 105208600Srdivackyunsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { 106208600Srdivacky while (A != B) { 107208600Srdivacky // Inner scopes are created after outer scopes and therefore have 108208600Srdivacky // higher indices. 109208600Srdivacky if (A < B) { 110208600Srdivacky assert(Scopes[B].ParentScope < B); 111208600Srdivacky B = Scopes[B].ParentScope; 112208600Srdivacky } else { 113208600Srdivacky assert(Scopes[A].ParentScope < A); 114208600Srdivacky A = Scopes[A].ParentScope; 115208600Srdivacky } 116208600Srdivacky } 117208600Srdivacky return A; 118208600Srdivacky} 119208600Srdivacky 120224145Sdimtypedef std::pair<unsigned,unsigned> ScopePair; 121224145Sdim 122193326Sed/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a 123193326Sed/// diagnostic that should be emitted if control goes over it. If not, return 0. 124224145Sdimstatic ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { 125193326Sed if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { 126243830Sdim unsigned InDiag = 0; 127193326Sed if (VD->getType()->isVariablyModifiedType()) 128208600Srdivacky InDiag = diag::note_protected_by_vla; 129208600Srdivacky 130224145Sdim if (VD->hasAttr<BlocksAttr>()) 131224145Sdim return ScopePair(diag::note_protected_by___block, 132224145Sdim diag::note_exits___block); 133224145Sdim 134224145Sdim if (VD->hasAttr<CleanupAttr>()) 135224145Sdim return ScopePair(diag::note_protected_by_cleanup, 136224145Sdim diag::note_exits_cleanup); 137224145Sdim 138234353Sdim if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) { 139224145Sdim switch (VD->getType().getObjCLifetime()) { 140224145Sdim case Qualifiers::OCL_None: 141224145Sdim case Qualifiers::OCL_ExplicitNone: 142224145Sdim case Qualifiers::OCL_Autoreleasing: 143224145Sdim break; 144224145Sdim 145224145Sdim case Qualifiers::OCL_Strong: 146224145Sdim case Qualifiers::OCL_Weak: 147224145Sdim return ScopePair(diag::note_protected_by_objc_ownership, 148224145Sdim diag::note_exits_objc_ownership); 149224145Sdim } 150224145Sdim } 151224145Sdim 152234353Sdim if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) { 153234353Sdim // C++11 [stmt.dcl]p3: 154224145Sdim // A program that jumps from a point where a variable with automatic 155224145Sdim // storage duration is not in scope to a point where it is in scope 156224145Sdim // is ill-formed unless the variable has scalar type, class type with 157224145Sdim // a trivial default constructor and a trivial destructor, a 158224145Sdim // cv-qualified version of one of these types, or an array of one of 159224145Sdim // the preceding types and is declared without an initializer. 160224145Sdim 161224145Sdim // C++03 [stmt.dcl.p3: 162224145Sdim // A program that jumps from a point where a local variable 163224145Sdim // with automatic storage duration is not in scope to a point 164224145Sdim // where it is in scope is ill-formed unless the variable has 165224145Sdim // POD type and is declared without an initializer. 166224145Sdim 167243830Sdim const Expr *Init = VD->getInit(); 168243830Sdim if (!Init) 169243830Sdim return ScopePair(InDiag, 0); 170224145Sdim 171243830Sdim const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init); 172243830Sdim if (EWC) 173243830Sdim Init = EWC->getSubExpr(); 174224145Sdim 175243830Sdim const MaterializeTemporaryExpr *M = NULL; 176243830Sdim Init = Init->findMaterializedTemporary(M); 177224145Sdim 178263508Sdim SmallVector<const Expr *, 2> CommaLHSs; 179243830Sdim SmallVector<SubobjectAdjustment, 2> Adjustments; 180263508Sdim Init = Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); 181224145Sdim 182243830Sdim QualType QT = Init->getType(); 183243830Sdim if (QT.isNull()) 184243830Sdim return ScopePair(diag::note_protected_by_variable_init, 0); 185224145Sdim 186243830Sdim const Type *T = QT.getTypePtr(); 187243830Sdim if (T->isArrayType()) 188243830Sdim T = T->getBaseElementTypeUnsafe(); 189243830Sdim 190243830Sdim const CXXRecordDecl *Record = T->getAsCXXRecordDecl(); 191243830Sdim if (!Record) 192243830Sdim return ScopePair(diag::note_protected_by_variable_init, 0); 193243830Sdim 194243830Sdim // If we need to call a non trivial destructor for this variable, 195243830Sdim // record an out diagnostic. 196243830Sdim unsigned OutDiag = 0; 197243830Sdim if (!Init->isGLValue() && !Record->hasTrivialDestructor()) 198243830Sdim OutDiag = diag::note_exits_dtor; 199243830Sdim 200243830Sdim if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) { 201243830Sdim const CXXConstructorDecl *ctor = cce->getConstructor(); 202263508Sdim // For a variable declared without an initializer, we will have 203263508Sdim // call-style initialization and the initializer will be the 204263508Sdim // CXXConstructExpr with no intervening nodes. 205263508Sdim if (ctor->isTrivial() && ctor->isDefaultConstructor() && 206263508Sdim VD->getInit() == Init && VD->getInitStyle() == VarDecl::CallInit) { 207243830Sdim if (OutDiag) 208243830Sdim InDiag = diag::note_protected_by_variable_nontriv_destructor; 209243830Sdim else if (!Record->isPOD()) 210243830Sdim InDiag = diag::note_protected_by_variable_non_pod; 211243830Sdim return ScopePair(InDiag, OutDiag); 212243830Sdim } 213210299Sed } 214243830Sdim 215243830Sdim return ScopePair(diag::note_protected_by_variable_init, OutDiag); 216208600Srdivacky } 217243830Sdim 218243830Sdim return ScopePair(InDiag, 0); 219208600Srdivacky } 220208600Srdivacky 221208600Srdivacky if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { 222193326Sed if (TD->getUnderlyingType()->isVariablyModifiedType()) 223224145Sdim return ScopePair(diag::note_protected_by_vla_typedef, 0); 224193326Sed } 225198092Srdivacky 226221345Sdim if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { 227221345Sdim if (TD->getUnderlyingType()->isVariablyModifiedType()) 228224145Sdim return ScopePair(diag::note_protected_by_vla_type_alias, 0); 229221345Sdim } 230221345Sdim 231224145Sdim return ScopePair(0U, 0U); 232193326Sed} 233193326Sed 234210299Sed/// \brief Build scope information for a declaration that is part of a DeclStmt. 235210299Sedvoid JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { 236210299Sed // If this decl causes a new scope, push and switch to it. 237224145Sdim std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D); 238210299Sed if (Diags.first || Diags.second) { 239210299Sed Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, 240210299Sed D->getLocation())); 241210299Sed ParentScope = Scopes.size()-1; 242210299Sed } 243210299Sed 244210299Sed // If the decl has an initializer, walk it with the potentially new 245210299Sed // scope we just installed. 246210299Sed if (VarDecl *VD = dyn_cast<VarDecl>(D)) 247210299Sed if (Expr *Init = VD->getInit()) 248210299Sed BuildScopeInformation(Init, ParentScope); 249210299Sed} 250193326Sed 251224145Sdim/// \brief Build scope information for a captured block literal variables. 252224145Sdimvoid JumpScopeChecker::BuildScopeInformation(VarDecl *D, 253224145Sdim const BlockDecl *BDecl, 254224145Sdim unsigned &ParentScope) { 255224145Sdim // exclude captured __block variables; there's no destructor 256224145Sdim // associated with the block literal for them. 257224145Sdim if (D->hasAttr<BlocksAttr>()) 258224145Sdim return; 259224145Sdim QualType T = D->getType(); 260224145Sdim QualType::DestructionKind destructKind = T.isDestructedType(); 261224145Sdim if (destructKind != QualType::DK_none) { 262224145Sdim std::pair<unsigned,unsigned> Diags; 263224145Sdim switch (destructKind) { 264224145Sdim case QualType::DK_cxx_destructor: 265224145Sdim Diags = ScopePair(diag::note_enters_block_captures_cxx_obj, 266224145Sdim diag::note_exits_block_captures_cxx_obj); 267224145Sdim break; 268224145Sdim case QualType::DK_objc_strong_lifetime: 269224145Sdim Diags = ScopePair(diag::note_enters_block_captures_strong, 270224145Sdim diag::note_exits_block_captures_strong); 271224145Sdim break; 272224145Sdim case QualType::DK_objc_weak_lifetime: 273224145Sdim Diags = ScopePair(diag::note_enters_block_captures_weak, 274224145Sdim diag::note_exits_block_captures_weak); 275224145Sdim break; 276224145Sdim case QualType::DK_none: 277234353Sdim llvm_unreachable("non-lifetime captured variable"); 278224145Sdim } 279224145Sdim SourceLocation Loc = D->getLocation(); 280224145Sdim if (Loc.isInvalid()) 281224145Sdim Loc = BDecl->getLocation(); 282224145Sdim Scopes.push_back(GotoScope(ParentScope, 283224145Sdim Diags.first, Diags.second, Loc)); 284224145Sdim ParentScope = Scopes.size()-1; 285224145Sdim } 286224145Sdim} 287224145Sdim 288193326Sed/// BuildScopeInformation - The statements from CI to CE are known to form a 289193326Sed/// coherent VLA scope with a specified parent node. Walk through the 290193326Sed/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively 291193326Sed/// walking the AST as needed. 292224145Sdimvoid JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) { 293224145Sdim // If this is a statement, rather than an expression, scopes within it don't 294224145Sdim // propagate out into the enclosing scope. Otherwise we have to worry 295224145Sdim // about block literals, which have the lifetime of their enclosing statement. 296224145Sdim unsigned independentParentScope = origParentScope; 297224145Sdim unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S)) 298224145Sdim ? origParentScope : independentParentScope); 299224145Sdim 300210299Sed bool SkipFirstSubStmt = false; 301210299Sed 302193326Sed // If we found a label, remember that it is in ParentScope scope. 303208600Srdivacky switch (S->getStmtClass()) { 304208600Srdivacky case Stmt::AddrLabelExprClass: 305208600Srdivacky IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel()); 306208600Srdivacky break; 307208600Srdivacky 308208600Srdivacky case Stmt::IndirectGotoStmtClass: 309218893Sdim // "goto *&&lbl;" is a special case which we treat as equivalent 310218893Sdim // to a normal goto. In addition, we don't calculate scope in the 311218893Sdim // operand (to avoid recording the address-of-label use), which 312218893Sdim // works only because of the restricted set of expressions which 313218893Sdim // we detect as constant targets. 314218893Sdim if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { 315218893Sdim LabelAndGotoScopes[S] = ParentScope; 316218893Sdim Jumps.push_back(S); 317218893Sdim return; 318218893Sdim } 319218893Sdim 320208600Srdivacky LabelAndGotoScopes[S] = ParentScope; 321208600Srdivacky IndirectJumps.push_back(cast<IndirectGotoStmt>(S)); 322208600Srdivacky break; 323208600Srdivacky 324210299Sed case Stmt::SwitchStmtClass: 325210299Sed // Evaluate the condition variable before entering the scope of the switch 326210299Sed // statement. 327210299Sed if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { 328210299Sed BuildScopeInformation(Var, ParentScope); 329210299Sed SkipFirstSubStmt = true; 330210299Sed } 331210299Sed // Fall through 332210299Sed 333208600Srdivacky case Stmt::GotoStmtClass: 334193326Sed // Remember both what scope a goto is in as well as the fact that we have 335193326Sed // it. This makes the second scan not have to walk the AST again. 336193326Sed LabelAndGotoScopes[S] = ParentScope; 337193326Sed Jumps.push_back(S); 338208600Srdivacky break; 339208600Srdivacky 340243830Sdim case Stmt::CXXTryStmtClass: { 341243830Sdim CXXTryStmt *TS = cast<CXXTryStmt>(S); 342243830Sdim unsigned newParentScope; 343243830Sdim Scopes.push_back(GotoScope(ParentScope, 344243830Sdim diag::note_protected_by_cxx_try, 345243830Sdim diag::note_exits_cxx_try, 346243830Sdim TS->getSourceRange().getBegin())); 347243830Sdim if (Stmt *TryBlock = TS->getTryBlock()) 348243830Sdim BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); 349243830Sdim 350243830Sdim // Jump from the catch into the try is not allowed either. 351243830Sdim for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { 352243830Sdim CXXCatchStmt *CS = TS->getHandler(I); 353243830Sdim Scopes.push_back(GotoScope(ParentScope, 354243830Sdim diag::note_protected_by_cxx_catch, 355243830Sdim diag::note_exits_cxx_catch, 356243830Sdim CS->getSourceRange().getBegin())); 357243830Sdim BuildScopeInformation(CS->getHandlerBlock(), 358243830Sdim (newParentScope = Scopes.size()-1)); 359243830Sdim } 360243830Sdim return; 361243830Sdim } 362243830Sdim 363208600Srdivacky default: 364208600Srdivacky break; 365193326Sed } 366198092Srdivacky 367218893Sdim for (Stmt::child_range CI = S->children(); CI; ++CI) { 368210299Sed if (SkipFirstSubStmt) { 369210299Sed SkipFirstSubStmt = false; 370210299Sed continue; 371210299Sed } 372210299Sed 373193326Sed Stmt *SubStmt = *CI; 374193326Sed if (SubStmt == 0) continue; 375198092Srdivacky 376212904Sdim // Cases, labels, and defaults aren't "scope parents". It's also 377212904Sdim // important to handle these iteratively instead of recursively in 378212904Sdim // order to avoid blowing out the stack. 379212904Sdim while (true) { 380212904Sdim Stmt *Next; 381218893Sdim if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt)) 382218893Sdim Next = CS->getSubStmt(); 383218893Sdim else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt)) 384218893Sdim Next = DS->getSubStmt(); 385218893Sdim else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) 386218893Sdim Next = LS->getSubStmt(); 387212904Sdim else 388212904Sdim break; 389212904Sdim 390212904Sdim LabelAndGotoScopes[SubStmt] = ParentScope; 391212904Sdim SubStmt = Next; 392212904Sdim } 393212904Sdim 394193326Sed // If this is a declstmt with a VLA definition, it defines a scope from here 395193326Sed // to the end of the containing context. 396193326Sed if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { 397204643Srdivacky // The decl statement creates a scope if any of the decls in it are VLAs 398204643Srdivacky // or have the cleanup attribute. 399193326Sed for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 400210299Sed I != E; ++I) 401210299Sed BuildScopeInformation(*I, ParentScope); 402193326Sed continue; 403193326Sed } 404193326Sed // Disallow jumps into any part of an @try statement by pushing a scope and 405193326Sed // walking all sub-stmts in that scope. 406193326Sed if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { 407224145Sdim unsigned newParentScope; 408193326Sed // Recursively walk the AST for the @try part. 409208600Srdivacky Scopes.push_back(GotoScope(ParentScope, 410208600Srdivacky diag::note_protected_by_objc_try, 411208600Srdivacky diag::note_exits_objc_try, 412193326Sed AT->getAtTryLoc())); 413193326Sed if (Stmt *TryPart = AT->getTryBody()) 414224145Sdim BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1)); 415193326Sed 416193326Sed // Jump from the catch to the finally or try is not valid. 417207619Srdivacky for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { 418207619Srdivacky ObjCAtCatchStmt *AC = AT->getCatchStmt(I); 419193326Sed Scopes.push_back(GotoScope(ParentScope, 420193326Sed diag::note_protected_by_objc_catch, 421208600Srdivacky diag::note_exits_objc_catch, 422193326Sed AC->getAtCatchLoc())); 423198092Srdivacky // @catches are nested and it isn't 424224145Sdim BuildScopeInformation(AC->getCatchBody(), 425224145Sdim (newParentScope = Scopes.size()-1)); 426193326Sed } 427198092Srdivacky 428193326Sed // Jump from the finally to the try or catch is not valid. 429193326Sed if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { 430193326Sed Scopes.push_back(GotoScope(ParentScope, 431193326Sed diag::note_protected_by_objc_finally, 432208600Srdivacky diag::note_exits_objc_finally, 433193326Sed AF->getAtFinallyLoc())); 434224145Sdim BuildScopeInformation(AF, (newParentScope = Scopes.size()-1)); 435193326Sed } 436198092Srdivacky 437193326Sed continue; 438193326Sed } 439224145Sdim 440224145Sdim unsigned newParentScope; 441193326Sed // Disallow jumps into the protected statement of an @synchronized, but 442193326Sed // allow jumps into the object expression it protects. 443193326Sed if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ 444193326Sed // Recursively walk the AST for the @synchronized object expr, it is 445193326Sed // evaluated in the normal scope. 446193326Sed BuildScopeInformation(AS->getSynchExpr(), ParentScope); 447198092Srdivacky 448193326Sed // Recursively walk the AST for the @synchronized part, protected by a new 449193326Sed // scope. 450193326Sed Scopes.push_back(GotoScope(ParentScope, 451193326Sed diag::note_protected_by_objc_synchronized, 452208600Srdivacky diag::note_exits_objc_synchronized, 453193326Sed AS->getAtSynchronizedLoc())); 454224145Sdim BuildScopeInformation(AS->getSynchBody(), 455224145Sdim (newParentScope = Scopes.size()-1)); 456193326Sed continue; 457193326Sed } 458193326Sed 459224145Sdim // Disallow jumps into the protected statement of an @autoreleasepool. 460224145Sdim if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){ 461224145Sdim // Recursively walk the AST for the @autoreleasepool part, protected by a new 462224145Sdim // scope. 463224145Sdim Scopes.push_back(GotoScope(ParentScope, 464224145Sdim diag::note_protected_by_objc_autoreleasepool, 465224145Sdim diag::note_exits_objc_autoreleasepool, 466224145Sdim AS->getAtLoc())); 467224145Sdim BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1)); 468224145Sdim continue; 469224145Sdim } 470243830Sdim 471243830Sdim // Disallow jumps past full-expressions that use blocks with 472243830Sdim // non-trivial cleanups of their captures. This is theoretically 473243830Sdim // implementable but a lot of work which we haven't felt up to doing. 474243830Sdim if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) { 475243830Sdim for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { 476243830Sdim const BlockDecl *BDecl = EWC->getObject(i); 477224145Sdim for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(), 478224145Sdim ce = BDecl->capture_end(); ci != ce; ++ci) { 479224145Sdim VarDecl *variable = ci->getVariable(); 480224145Sdim BuildScopeInformation(variable, BDecl, ParentScope); 481224145Sdim } 482243830Sdim } 483224145Sdim } 484224145Sdim 485193326Sed // Recursively walk the AST. 486193326Sed BuildScopeInformation(SubStmt, ParentScope); 487193326Sed } 488193326Sed} 489193326Sed 490193326Sed/// VerifyJumps - Verify each element of the Jumps array to see if they are 491193326Sed/// valid, emitting diagnostics if not. 492193326Sedvoid JumpScopeChecker::VerifyJumps() { 493193326Sed while (!Jumps.empty()) { 494193326Sed Stmt *Jump = Jumps.pop_back_val(); 495198092Srdivacky 496198092Srdivacky // With a goto, 497193326Sed if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { 498218893Sdim CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), 499226633Sdim diag::err_goto_into_protected_scope, 500234353Sdim diag::warn_goto_into_protected_scope, 501234353Sdim diag::warn_cxx98_compat_goto_into_protected_scope); 502193326Sed continue; 503193326Sed } 504198092Srdivacky 505218893Sdim // We only get indirect gotos here when they have a constant target. 506218893Sdim if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { 507218893Sdim LabelDecl *Target = IGS->getConstantTarget(); 508218893Sdim CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), 509226633Sdim diag::err_goto_into_protected_scope, 510234353Sdim diag::warn_goto_into_protected_scope, 511234353Sdim diag::warn_cxx98_compat_goto_into_protected_scope); 512218893Sdim continue; 513218893Sdim } 514218893Sdim 515208600Srdivacky SwitchStmt *SS = cast<SwitchStmt>(Jump); 516208600Srdivacky for (SwitchCase *SC = SS->getSwitchCaseList(); SC; 517208600Srdivacky SC = SC->getNextSwitchCase()) { 518208600Srdivacky assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); 519249423Sdim SourceLocation Loc; 520249423Sdim if (CaseStmt *CS = dyn_cast<CaseStmt>(SC)) 521249423Sdim Loc = CS->getLocStart(); 522249423Sdim else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) 523249423Sdim Loc = DS->getLocStart(); 524249423Sdim else 525249423Sdim Loc = SC->getLocStart(); 526249423Sdim CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0, 527234353Sdim diag::warn_cxx98_compat_switch_into_protected_scope); 528193326Sed } 529208600Srdivacky } 530208600Srdivacky} 531193326Sed 532208600Srdivacky/// VerifyIndirectJumps - Verify whether any possible indirect jump 533208600Srdivacky/// might cross a protection boundary. Unlike direct jumps, indirect 534208600Srdivacky/// jumps count cleanups as protection boundaries: since there's no 535208600Srdivacky/// way to know where the jump is going, we can't implicitly run the 536208600Srdivacky/// right cleanups the way we can with direct jumps. 537208600Srdivacky/// 538208600Srdivacky/// Thus, an indirect jump is "trivial" if it bypasses no 539208600Srdivacky/// initializations and no teardowns. More formally, an indirect jump 540208600Srdivacky/// from A to B is trivial if the path out from A to DCA(A,B) is 541208600Srdivacky/// trivial and the path in from DCA(A,B) to B is trivial, where 542208600Srdivacky/// DCA(A,B) is the deepest common ancestor of A and B. 543208600Srdivacky/// Jump-triviality is transitive but asymmetric. 544208600Srdivacky/// 545208600Srdivacky/// A path in is trivial if none of the entered scopes have an InDiag. 546208600Srdivacky/// A path out is trivial is none of the exited scopes have an OutDiag. 547208600Srdivacky/// 548208600Srdivacky/// Under these definitions, this function checks that the indirect 549208600Srdivacky/// jump between A and B is trivial for every indirect goto statement A 550208600Srdivacky/// and every label B whose address was taken in the function. 551208600Srdivackyvoid JumpScopeChecker::VerifyIndirectJumps() { 552208600Srdivacky if (IndirectJumps.empty()) return; 553198092Srdivacky 554208600Srdivacky // If there aren't any address-of-label expressions in this function, 555208600Srdivacky // complain about the first indirect goto. 556208600Srdivacky if (IndirectJumpTargets.empty()) { 557208600Srdivacky S.Diag(IndirectJumps[0]->getGotoLoc(), 558208600Srdivacky diag::err_indirect_goto_without_addrlabel); 559208600Srdivacky return; 560208600Srdivacky } 561198092Srdivacky 562208600Srdivacky // Collect a single representative of every scope containing an 563208600Srdivacky // indirect goto. For most code bases, this substantially cuts 564208600Srdivacky // down on the number of jump sites we'll have to consider later. 565208600Srdivacky typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; 566226633Sdim SmallVector<JumpScope, 32> JumpScopes; 567208600Srdivacky { 568208600Srdivacky llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; 569226633Sdim for (SmallVectorImpl<IndirectGotoStmt*>::iterator 570208600Srdivacky I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { 571208600Srdivacky IndirectGotoStmt *IG = *I; 572208600Srdivacky assert(LabelAndGotoScopes.count(IG) && 573208600Srdivacky "indirect jump didn't get added to scopes?"); 574208600Srdivacky unsigned IGScope = LabelAndGotoScopes[IG]; 575208600Srdivacky IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; 576208600Srdivacky if (!Entry) Entry = IG; 577208600Srdivacky } 578208600Srdivacky JumpScopes.reserve(JumpScopesMap.size()); 579208600Srdivacky for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator 580208600Srdivacky I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) 581208600Srdivacky JumpScopes.push_back(*I); 582208600Srdivacky } 583198092Srdivacky 584208600Srdivacky // Collect a single representative of every scope containing a 585208600Srdivacky // label whose address was taken somewhere in the function. 586208600Srdivacky // For most code bases, there will be only one such scope. 587218893Sdim llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; 588226633Sdim for (SmallVectorImpl<LabelDecl*>::iterator 589208600Srdivacky I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); 590208600Srdivacky I != E; ++I) { 591218893Sdim LabelDecl *TheLabel = *I; 592218893Sdim assert(LabelAndGotoScopes.count(TheLabel->getStmt()) && 593208600Srdivacky "Referenced label didn't get added to scopes?"); 594218893Sdim unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; 595218893Sdim LabelDecl *&Target = TargetScopes[LabelScope]; 596208600Srdivacky if (!Target) Target = TheLabel; 597208600Srdivacky } 598208600Srdivacky 599208600Srdivacky // For each target scope, make sure it's trivially reachable from 600208600Srdivacky // every scope containing a jump site. 601208600Srdivacky // 602208600Srdivacky // A path between scopes always consists of exitting zero or more 603208600Srdivacky // scopes, then entering zero or more scopes. We build a set of 604208600Srdivacky // of scopes S from which the target scope can be trivially 605208600Srdivacky // entered, then verify that every jump scope can be trivially 606208600Srdivacky // exitted to reach a scope in S. 607208600Srdivacky llvm::BitVector Reachable(Scopes.size(), false); 608218893Sdim for (llvm::DenseMap<unsigned,LabelDecl*>::iterator 609208600Srdivacky TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { 610208600Srdivacky unsigned TargetScope = TI->first; 611218893Sdim LabelDecl *TargetLabel = TI->second; 612208600Srdivacky 613208600Srdivacky Reachable.reset(); 614208600Srdivacky 615208600Srdivacky // Mark all the enclosing scopes from which you can safely jump 616208600Srdivacky // into the target scope. 'Min' will end up being the index of 617208600Srdivacky // the shallowest such scope. 618208600Srdivacky unsigned Min = TargetScope; 619208600Srdivacky while (true) { 620208600Srdivacky Reachable.set(Min); 621208600Srdivacky 622208600Srdivacky // Don't go beyond the outermost scope. 623208600Srdivacky if (Min == 0) break; 624208600Srdivacky 625208600Srdivacky // Stop if we can't trivially enter the current scope. 626208600Srdivacky if (Scopes[Min].InDiag) break; 627208600Srdivacky 628208600Srdivacky Min = Scopes[Min].ParentScope; 629193326Sed } 630193326Sed 631208600Srdivacky // Walk through all the jump sites, checking that they can trivially 632208600Srdivacky // reach this label scope. 633226633Sdim for (SmallVectorImpl<JumpScope>::iterator 634208600Srdivacky I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { 635208600Srdivacky unsigned Scope = I->first; 636208600Srdivacky 637208600Srdivacky // Walk out the "scope chain" for this scope, looking for a scope 638208600Srdivacky // we've marked reachable. For well-formed code this amortizes 639208600Srdivacky // to O(JumpScopes.size() / Scopes.size()): we only iterate 640208600Srdivacky // when we see something unmarked, and in well-formed code we 641208600Srdivacky // mark everything we iterate past. 642208600Srdivacky bool IsReachable = false; 643208600Srdivacky while (true) { 644208600Srdivacky if (Reachable.test(Scope)) { 645208600Srdivacky // If we find something reachable, mark all the scopes we just 646208600Srdivacky // walked through as reachable. 647208600Srdivacky for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) 648208600Srdivacky Reachable.set(S); 649208600Srdivacky IsReachable = true; 650208600Srdivacky break; 651208600Srdivacky } 652208600Srdivacky 653208600Srdivacky // Don't walk out if we've reached the top-level scope or we've 654208600Srdivacky // gotten shallower than the shallowest reachable scope. 655208600Srdivacky if (Scope == 0 || Scope < Min) break; 656208600Srdivacky 657208600Srdivacky // Don't walk out through an out-diagnostic. 658208600Srdivacky if (Scopes[Scope].OutDiag) break; 659208600Srdivacky 660208600Srdivacky Scope = Scopes[Scope].ParentScope; 661208600Srdivacky } 662208600Srdivacky 663208600Srdivacky // Only diagnose if we didn't find something. 664208600Srdivacky if (IsReachable) continue; 665208600Srdivacky 666208600Srdivacky DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); 667193326Sed } 668193326Sed } 669193326Sed} 670193326Sed 671234353Sdim/// Return true if a particular error+note combination must be downgraded to a 672234353Sdim/// warning in Microsoft mode. 673234353Sdimstatic bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) { 674234353Sdim return (JumpDiag == diag::err_goto_into_protected_scope && 675234353Sdim (InDiagNote == diag::note_protected_by_variable_init || 676234353Sdim InDiagNote == diag::note_protected_by_variable_nontriv_destructor)); 677234353Sdim} 678234353Sdim 679234353Sdim/// Return true if a particular note should be downgraded to a compatibility 680234353Sdim/// warning in C++11 mode. 681234353Sdimstatic bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) { 682249423Sdim return S.getLangOpts().CPlusPlus11 && 683234353Sdim InDiagNote == diag::note_protected_by_variable_non_pod; 684234353Sdim} 685234353Sdim 686234353Sdim/// Produce primary diagnostic for an indirect jump statement. 687234353Sdimstatic void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump, 688234353Sdim LabelDecl *Target, bool &Diagnosed) { 689234353Sdim if (Diagnosed) 690234353Sdim return; 691234353Sdim S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); 692234353Sdim S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); 693234353Sdim Diagnosed = true; 694234353Sdim} 695234353Sdim 696234353Sdim/// Produce note diagnostics for a jump into a protected scope. 697234353Sdimvoid JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) { 698234353Sdim assert(!ToScopes.empty()); 699234353Sdim for (unsigned I = 0, E = ToScopes.size(); I != E; ++I) 700234353Sdim if (Scopes[ToScopes[I]].InDiag) 701234353Sdim S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag); 702234353Sdim} 703234353Sdim 704208600Srdivacky/// Diagnose an indirect jump which is known to cross scopes. 705208600Srdivackyvoid JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, 706208600Srdivacky unsigned JumpScope, 707218893Sdim LabelDecl *Target, 708208600Srdivacky unsigned TargetScope) { 709208600Srdivacky assert(JumpScope != TargetScope); 710208600Srdivacky 711208600Srdivacky unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope); 712234353Sdim bool Diagnosed = false; 713208600Srdivacky 714208600Srdivacky // Walk out the scope chain until we reach the common ancestor. 715208600Srdivacky for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope) 716234353Sdim if (Scopes[I].OutDiag) { 717234353Sdim DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed); 718208600Srdivacky S.Diag(Scopes[I].Loc, Scopes[I].OutDiag); 719234353Sdim } 720208600Srdivacky 721234353Sdim SmallVector<unsigned, 10> ToScopesCXX98Compat; 722234353Sdim 723208600Srdivacky // Now walk into the scopes containing the label whose address was taken. 724208600Srdivacky for (unsigned I = TargetScope; I != Common; I = Scopes[I].ParentScope) 725234353Sdim if (IsCXX98CompatWarning(S, Scopes[I].InDiag)) 726234353Sdim ToScopesCXX98Compat.push_back(I); 727234353Sdim else if (Scopes[I].InDiag) { 728234353Sdim DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed); 729208600Srdivacky S.Diag(Scopes[I].Loc, Scopes[I].InDiag); 730234353Sdim } 731208600Srdivacky 732234353Sdim // Diagnose this jump if it would be ill-formed in C++98. 733234353Sdim if (!Diagnosed && !ToScopesCXX98Compat.empty()) { 734234353Sdim S.Diag(Jump->getGotoLoc(), 735234353Sdim diag::warn_cxx98_compat_indirect_goto_in_protected_scope); 736234353Sdim S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target); 737234353Sdim NoteJumpIntoScopes(ToScopesCXX98Compat); 738234353Sdim } 739226633Sdim} 740226633Sdim 741193326Sed/// CheckJump - Validate that the specified jump statement is valid: that it is 742193326Sed/// jumping within or out of its current scope, not into a deeper one. 743226633Sdimvoid JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, 744234353Sdim unsigned JumpDiagError, unsigned JumpDiagWarning, 745234353Sdim unsigned JumpDiagCXX98Compat) { 746193326Sed assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); 747193326Sed unsigned FromScope = LabelAndGotoScopes[From]; 748193326Sed 749193326Sed assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); 750193326Sed unsigned ToScope = LabelAndGotoScopes[To]; 751198092Srdivacky 752193326Sed // Common case: exactly the same scope, which is fine. 753193326Sed if (FromScope == ToScope) return; 754198092Srdivacky 755208600Srdivacky unsigned CommonScope = GetDeepestCommonScope(FromScope, ToScope); 756198092Srdivacky 757208600Srdivacky // It's okay to jump out from a nested scope. 758208600Srdivacky if (CommonScope == ToScope) return; 759198092Srdivacky 760208600Srdivacky // Pull out (and reverse) any scopes we might need to diagnose skipping. 761234353Sdim SmallVector<unsigned, 10> ToScopesCXX98Compat; 762226633Sdim SmallVector<unsigned, 10> ToScopesError; 763226633Sdim SmallVector<unsigned, 10> ToScopesWarning; 764226633Sdim for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { 765234353Sdim if (S.getLangOpts().MicrosoftMode && JumpDiagWarning != 0 && 766226633Sdim IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) 767226633Sdim ToScopesWarning.push_back(I); 768234353Sdim else if (IsCXX98CompatWarning(S, Scopes[I].InDiag)) 769234353Sdim ToScopesCXX98Compat.push_back(I); 770226633Sdim else if (Scopes[I].InDiag) 771226633Sdim ToScopesError.push_back(I); 772226633Sdim } 773193326Sed 774226633Sdim // Handle warnings. 775226633Sdim if (!ToScopesWarning.empty()) { 776226633Sdim S.Diag(DiagLoc, JumpDiagWarning); 777234353Sdim NoteJumpIntoScopes(ToScopesWarning); 778226633Sdim } 779193326Sed 780226633Sdim // Handle errors. 781226633Sdim if (!ToScopesError.empty()) { 782226633Sdim S.Diag(DiagLoc, JumpDiagError); 783234353Sdim NoteJumpIntoScopes(ToScopesError); 784226633Sdim } 785234353Sdim 786234353Sdim // Handle -Wc++98-compat warnings if the jump is well-formed. 787234353Sdim if (ToScopesError.empty() && !ToScopesCXX98Compat.empty()) { 788234353Sdim S.Diag(DiagLoc, JumpDiagCXX98Compat); 789234353Sdim NoteJumpIntoScopes(ToScopesCXX98Compat); 790234353Sdim } 791193326Sed} 792193326Sed 793193326Sedvoid Sema::DiagnoseInvalidJumps(Stmt *Body) { 794199482Srdivacky (void)JumpScopeChecker(Body, *this); 795193326Sed} 796