/// VerifyJumps - Verify each element of the Jumps array to see if they are /// valid, emitting diagnostics if not. void JumpScopeChecker::VerifyJumps() { while (!Jumps.empty()) { Stmt *Jump = Jumps.pop_back_val(); // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), diag::err_goto_into_protected_scope, diag::warn_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); continue; } // We only get indirect gotos here when they have a constant target. if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { LabelDecl *Target = IGS->getConstantTarget(); CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), diag::err_goto_into_protected_scope, diag::warn_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); continue; } SwitchStmt *SS = cast<SwitchStmt>(Jump); for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); CheckJump(SS, SC, SC->getLocStart(), diag::err_switch_into_protected_scope, 0, diag::warn_cxx98_compat_switch_into_protected_scope); } } }
StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, llvm::SMLoc Location, bool Create) { SourceLocation Loc = translateLocation(LSM, Location); LabelDecl *Label = TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); return Label->getMSAsmLabel(); }
/// VerifyJumps - Verify each element of the Jumps array to see if they are /// valid, emitting diagnostics if not. void JumpScopeChecker::VerifyJumps() { while (!Jumps.empty()) { Stmt *Jump = Jumps.pop_back_val(); // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { // The label may not have a statement if it's coming from inline MS ASM. if (GS->getLabel()->getStmt()) { CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), diag::err_goto_into_protected_scope, diag::ext_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); } CheckGotoStmt(GS); continue; } // We only get indirect gotos here when they have a constant target. if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { LabelDecl *Target = IGS->getConstantTarget(); CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), diag::err_goto_into_protected_scope, diag::ext_goto_into_protected_scope, diag::warn_cxx98_compat_goto_into_protected_scope); continue; } SwitchStmt *SS = cast<SwitchStmt>(Jump); for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC))) continue; SourceLocation Loc; if (CaseStmt *CS = dyn_cast<CaseStmt>(SC)) Loc = CS->getLocStart(); else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) Loc = DS->getLocStart(); else Loc = SC->getLocStart(); CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0, diag::warn_cxx98_compat_switch_into_protected_scope); } } }
LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate) { LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName), Location); if (Label->isMSAsmLabel()) { // If we have previously created this label implicitly, mark it as used. Label->markUsed(Context); } else { // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; llvm::raw_string_ostream OS(InternalName); // Create an internal name for the label. The name should not be a valid mangled // name, and should be unique. We use a dot to make the name an invalid mangled // name. OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName; Label->setMSAsmLabel(OS.str()); } if (AlwaysCreate) { // The label might have been created implicitly from a previously encountered // goto statement. So, for both newly created and looked up labels, we mark // them as resolved. Label->setMSAsmLabelResolved(); } // Adjust their location for being able to generate accurate diagnostics. Label->setLocation(Location); return Label; }
LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate) { LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName), Location); if (Label->isMSAsmLabel()) { // If we have previously created this label implicitly, mark it as used. Label->markUsed(Context); } else { // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; llvm::raw_string_ostream OS(InternalName); // Create an internal name for the label. The name should not be a valid // mangled name, and should be unique. We use a dot to make the name an // invalid mangled name. We use LLVM's inline asm ${:uid} escape so that a // unique label is generated each time this blob is emitted, even after // inlining or LTO. OS << "__MSASMLABEL_.${:uid}__"; for (char C : ExternalLabelName) { OS << C; // We escape '$' in asm strings by replacing it with "$$" if (C == '$') OS << '$'; } Label->setMSAsmLabel(OS.str()); } if (AlwaysCreate) { // The label might have been created implicitly from a previously encountered // goto statement. So, for both newly created and looked up labels, we mark // them as resolved. Label->setMSAsmLabelResolved(); } // Adjust their location for being able to generate accurate diagnostics. Label->setLocation(Location); return Label; }
/// VerifyIndirectJumps - Verify whether any possible indirect jump /// might cross a protection boundary. Unlike direct jumps, indirect /// jumps count cleanups as protection boundaries: since there's no /// way to know where the jump is going, we can't implicitly run the /// right cleanups the way we can with direct jumps. /// /// Thus, an indirect jump is "trivial" if it bypasses no /// initializations and no teardowns. More formally, an indirect jump /// from A to B is trivial if the path out from A to DCA(A,B) is /// trivial and the path in from DCA(A,B) to B is trivial, where /// DCA(A,B) is the deepest common ancestor of A and B. /// Jump-triviality is transitive but asymmetric. /// /// A path in is trivial if none of the entered scopes have an InDiag. /// A path out is trivial is none of the exited scopes have an OutDiag. /// /// Under these definitions, this function checks that the indirect /// jump between A and B is trivial for every indirect goto statement A /// and every label B whose address was taken in the function. void JumpScopeChecker::VerifyIndirectJumps() { if (IndirectJumps.empty()) return; // If there aren't any address-of-label expressions in this function, // complain about the first indirect goto. if (IndirectJumpTargets.empty()) { S.Diag(IndirectJumps[0]->getGotoLoc(), diag::err_indirect_goto_without_addrlabel); return; } // Collect a single representative of every scope containing an // indirect goto. For most code bases, this substantially cuts // down on the number of jump sites we'll have to consider later. typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; SmallVector<JumpScope, 32> JumpScopes; { llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; for (SmallVectorImpl<IndirectGotoStmt*>::iterator I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { IndirectGotoStmt *IG = *I; assert(LabelAndGotoScopes.count(IG) && "indirect jump didn't get added to scopes?"); unsigned IGScope = LabelAndGotoScopes[IG]; IndirectGotoStmt *&Entry = JumpScopesMap[IGScope]; if (!Entry) Entry = IG; } JumpScopes.reserve(JumpScopesMap.size()); for (llvm::DenseMap<unsigned, IndirectGotoStmt*>::iterator I = JumpScopesMap.begin(), E = JumpScopesMap.end(); I != E; ++I) JumpScopes.push_back(*I); } // Collect a single representative of every scope containing a // label whose address was taken somewhere in the function. // For most code bases, there will be only one such scope. llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; for (SmallVectorImpl<LabelDecl*>::iterator I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); I != E; ++I) { LabelDecl *TheLabel = *I; assert(LabelAndGotoScopes.count(TheLabel->getStmt()) && "Referenced label didn't get added to scopes?"); unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; LabelDecl *&Target = TargetScopes[LabelScope]; if (!Target) Target = TheLabel; } // For each target scope, make sure it's trivially reachable from // every scope containing a jump site. // // A path between scopes always consists of exitting zero or more // scopes, then entering zero or more scopes. We build a set of // of scopes S from which the target scope can be trivially // entered, then verify that every jump scope can be trivially // exitted to reach a scope in S. llvm::BitVector Reachable(Scopes.size(), false); for (llvm::DenseMap<unsigned,LabelDecl*>::iterator TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { unsigned TargetScope = TI->first; LabelDecl *TargetLabel = TI->second; Reachable.reset(); // Mark all the enclosing scopes from which you can safely jump // into the target scope. 'Min' will end up being the index of // the shallowest such scope. unsigned Min = TargetScope; while (true) { Reachable.set(Min); // Don't go beyond the outermost scope. if (Min == 0) break; // Stop if we can't trivially enter the current scope. if (Scopes[Min].InDiag) break; Min = Scopes[Min].ParentScope; } // Walk through all the jump sites, checking that they can trivially // reach this label scope. for (SmallVectorImpl<JumpScope>::iterator I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { unsigned Scope = I->first; // Walk out the "scope chain" for this scope, looking for a scope // we've marked reachable. For well-formed code this amortizes // to O(JumpScopes.size() / Scopes.size()): we only iterate // when we see something unmarked, and in well-formed code we // mark everything we iterate past. bool IsReachable = false; while (true) { if (Reachable.test(Scope)) { // If we find something reachable, mark all the scopes we just // walked through as reachable. for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) Reachable.set(S); IsReachable = true; break; } // Don't walk out if we've reached the top-level scope or we've // gotten shallower than the shallowest reachable scope. if (Scope == 0 || Scope < Min) break; // Don't walk out through an out-diagnostic. if (Scopes[Scope].OutDiag) break; Scope = Scopes[Scope].ParentScope; } // Only diagnose if we didn't find something. if (IsReachable) continue; DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope); } } }