|
@@ -65,8 +65,10 @@ class JumpScopeChecker {
|
|
|
llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes;
|
|
|
SmallVector<Stmt*, 16> Jumps;
|
|
|
|
|
|
- SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
|
|
|
+ SmallVector<Stmt*, 4> IndirectJumps;
|
|
|
+ SmallVector<Stmt*, 4> AsmJumps;
|
|
|
SmallVector<LabelDecl*, 4> IndirectJumpTargets;
|
|
|
+ SmallVector<LabelDecl*, 4> AsmJumpTargets;
|
|
|
public:
|
|
|
JumpScopeChecker(Stmt *Body, Sema &S);
|
|
|
private:
|
|
@@ -76,10 +78,10 @@ private:
|
|
|
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
|
|
|
|
|
|
void VerifyJumps();
|
|
|
- void VerifyIndirectJumps();
|
|
|
+ void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
|
|
|
void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
|
|
|
- void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
|
|
|
- LabelDecl *Target, unsigned TargetScope);
|
|
|
+ void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
|
|
|
+ unsigned TargetScope);
|
|
|
void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
|
|
|
unsigned JumpDiag, unsigned JumpDiagWarning,
|
|
|
unsigned JumpDiagCXX98Compat);
|
|
@@ -103,7 +105,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
|
|
|
|
|
|
// Check that all jumps we saw are kosher.
|
|
|
VerifyJumps();
|
|
|
- VerifyIndirectJumps();
|
|
|
+ VerifyIndirectOrAsmJumps(false);
|
|
|
+ VerifyIndirectOrAsmJumps(true);
|
|
|
}
|
|
|
|
|
|
/// GetDeepestCommonScope - Finds the innermost scope enclosing the
|
|
@@ -316,7 +319,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
|
|
}
|
|
|
|
|
|
LabelAndGotoScopes[S] = ParentScope;
|
|
|
- IndirectJumps.push_back(cast<IndirectGotoStmt>(S));
|
|
|
+ IndirectJumps.push_back(S);
|
|
|
break;
|
|
|
|
|
|
case Stmt::SwitchStmtClass:
|
|
@@ -339,6 +342,18 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
|
|
Jumps.push_back(S);
|
|
|
break;
|
|
|
|
|
|
+ case Stmt::GCCAsmStmtClass:
|
|
|
+ if (auto *GS = dyn_cast<GCCAsmStmt>(S))
|
|
|
+ if (GS->isAsmGoto()) {
|
|
|
+ // Remember both what scope a goto is in as well as the fact that we
|
|
|
+ // have it. This makes the second scan not have to walk the AST again.
|
|
|
+ LabelAndGotoScopes[S] = ParentScope;
|
|
|
+ AsmJumps.push_back(GS);
|
|
|
+ for (auto *E : GS->labels())
|
|
|
+ AsmJumpTargets.push_back(E->getLabel());
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case Stmt::IfStmtClass: {
|
|
|
IfStmt *IS = cast<IfStmt>(S);
|
|
|
if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck()))
|
|
@@ -629,14 +644,13 @@ void JumpScopeChecker::VerifyJumps() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// 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
|
|
|
+/// VerifyIndirectOrAsmJumps - Verify whether any possible indirect goto or
|
|
|
+/// asm goto jump might cross a protection boundary. Unlike direct jumps,
|
|
|
+/// indirect or asm goto 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/asm jump is "trivial" if it bypasses no
|
|
|
+/// initializations and no teardowns. More formally, an indirect/asm 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.
|
|
@@ -648,36 +662,41 @@ void JumpScopeChecker::VerifyJumps() {
|
|
|
/// 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;
|
|
|
-
|
|
|
+void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) {
|
|
|
+ SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps;
|
|
|
+ if (GotoJumps.empty())
|
|
|
+ return;
|
|
|
+ SmallVector<LabelDecl *, 4> JumpTargets =
|
|
|
+ IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets;
|
|
|
// 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(),
|
|
|
+ if (JumpTargets.empty()) {
|
|
|
+ assert(!IsAsmGoto &&"only indirect goto can get here");
|
|
|
+ S.Diag(GotoJumps[0]->getBeginLoc(),
|
|
|
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
|
|
|
+ // indirect or asm 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;
|
|
|
+ typedef std::pair<unsigned, Stmt*> 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;
|
|
|
+ llvm::DenseMap<unsigned, Stmt*> JumpScopesMap;
|
|
|
+ for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(),
|
|
|
+ E = GotoJumps.end();
|
|
|
+ I != E; ++I) {
|
|
|
+ Stmt *IG = *I;
|
|
|
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
|
|
|
continue;
|
|
|
unsigned IGScope = LabelAndGotoScopes[IG];
|
|
|
- IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
|
|
|
+ Stmt *&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)
|
|
|
+ for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(),
|
|
|
+ E = JumpScopesMap.end();
|
|
|
+ I != E; ++I)
|
|
|
JumpScopes.push_back(*I);
|
|
|
}
|
|
|
|
|
@@ -685,8 +704,8 @@ void JumpScopeChecker::VerifyIndirectJumps() {
|
|
|
// 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();
|
|
|
+ for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(),
|
|
|
+ E = JumpTargets.end();
|
|
|
I != E; ++I) {
|
|
|
LabelDecl *TheLabel = *I;
|
|
|
if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
|
|
@@ -763,7 +782,7 @@ void JumpScopeChecker::VerifyIndirectJumps() {
|
|
|
// Only diagnose if we didn't find something.
|
|
|
if (IsReachable) continue;
|
|
|
|
|
|
- DiagnoseIndirectJump(I->second, I->first, TargetLabel, TargetScope);
|
|
|
+ DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -784,12 +803,15 @@ static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
|
|
|
}
|
|
|
|
|
|
/// Produce primary diagnostic for an indirect jump statement.
|
|
|
-static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
|
|
|
- LabelDecl *Target, bool &Diagnosed) {
|
|
|
+static void DiagnoseIndirectOrAsmJumpStmt(Sema &S, Stmt *Jump,
|
|
|
+ LabelDecl *Target, bool &Diagnosed) {
|
|
|
if (Diagnosed)
|
|
|
return;
|
|
|
- S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
|
|
|
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
|
|
|
+ bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
|
|
|
+ S.Diag(Jump->getBeginLoc(), diag::err_indirect_goto_in_protected_scope)
|
|
|
+ << IsAsmGoto;
|
|
|
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
|
|
|
+ << IsAsmGoto;
|
|
|
Diagnosed = true;
|
|
|
}
|
|
|
|
|
@@ -803,10 +825,9 @@ void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
|
|
|
}
|
|
|
|
|
|
/// Diagnose an indirect jump which is known to cross scopes.
|
|
|
-void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
|
|
|
- unsigned JumpScope,
|
|
|
- LabelDecl *Target,
|
|
|
- unsigned TargetScope) {
|
|
|
+void JumpScopeChecker::DiagnoseIndirectOrAsmJump(Stmt *Jump, unsigned JumpScope,
|
|
|
+ LabelDecl *Target,
|
|
|
+ unsigned TargetScope) {
|
|
|
if (CHECK_PERMISSIVE(JumpScope == TargetScope))
|
|
|
return;
|
|
|
|
|
@@ -816,7 +837,7 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
|
|
|
// Walk out the scope chain until we reach the common ancestor.
|
|
|
for (unsigned I = JumpScope; I != Common; I = Scopes[I].ParentScope)
|
|
|
if (Scopes[I].OutDiag) {
|
|
|
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
|
|
|
+ DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
|
|
|
S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
|
|
|
}
|
|
|
|
|
@@ -827,15 +848,18 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
|
|
|
if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
|
|
|
ToScopesCXX98Compat.push_back(I);
|
|
|
else if (Scopes[I].InDiag) {
|
|
|
- DiagnoseIndirectJumpStmt(S, Jump, Target, Diagnosed);
|
|
|
+ DiagnoseIndirectOrAsmJumpStmt(S, Jump, Target, Diagnosed);
|
|
|
S.Diag(Scopes[I].Loc, Scopes[I].InDiag);
|
|
|
}
|
|
|
|
|
|
// Diagnose this jump if it would be ill-formed in C++98.
|
|
|
if (!Diagnosed && !ToScopesCXX98Compat.empty()) {
|
|
|
- S.Diag(Jump->getGotoLoc(),
|
|
|
- diag::warn_cxx98_compat_indirect_goto_in_protected_scope);
|
|
|
- S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
|
|
|
+ bool IsAsmGoto = isa<GCCAsmStmt>(Jump);
|
|
|
+ S.Diag(Jump->getBeginLoc(),
|
|
|
+ diag::warn_cxx98_compat_indirect_goto_in_protected_scope)
|
|
|
+ << IsAsmGoto;
|
|
|
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target)
|
|
|
+ << IsAsmGoto;
|
|
|
NoteJumpIntoScopes(ToScopesCXX98Compat);
|
|
|
}
|
|
|
}
|