]> granicus.if.org Git - clang/commitdiff
Start of checking for gotos which jump to an illegal destination.
authorEli Friedman <eli.friedman@gmail.com>
Sat, 28 Feb 2009 05:41:13 +0000 (05:41 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Sat, 28 Feb 2009 05:41:13 +0000 (05:41 +0000)
As far as I know, this catches all cases of jumping into the scope of a
variable with a variably modified type (excluding statement
expressions) in C.  This is missing some stuff we probably want to check
(other kinds of variably modified declarations, statement expressions,
indirect gotos/addresses of labels in a scope, ObjC @try/@finally, cleanup
attribute), the diagnostics aren't very good, and it's not particularly
efficient, but it's a decent start.

This patch is a slightly modified version of the patch I attached to
PR3259, and it fixes that bug.  I was sort of planning on improving
it, but I think it's okay as-is, especially since it looks like CodeGen
doesn't have any use for this sort of data structure.  The only
significant change I can think of from the version I attached to PR3259
is that this version skips running the checking code when a function
doesn't contain any labels.

This patch doesn't cover case statements, which also need similar
checking; I'm not sure how we should deal with that. Extending the goto
checking to also check case statements wouldn't be too hard; it's just a
matter of keeping track of the scope of the closest switch and checking that
the scope of every case is the same as the scope of the switch.  That said,
it would likely be a performance hit to run this check on every
function (it's an extra pass over the entire function), so we probably want
some other solution.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65678 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/Sema/scope-check.c [new file with mode: 0644]

index e1c0af465936d3b1b36db4a025290f38b184969a..99b61cc8ffd668c7e7713f9e53c6007076007f4c 100644 (file)
@@ -744,6 +744,9 @@ DIAG(err_redefinition_of_label, ERROR,
 DIAG(err_undeclared_label_use, ERROR,
      "use of undeclared label '%0'")
 
+DIAG(err_goto_into_scope, ERROR,
+     "illegal jump (scoping violation)")
+
 DIAG(ext_implicit_function_decl, EXTENSION,
      "implicit declaration of function %0 is invalid in C99")
 
index 45ea16df5350375bc221d14aaed2d1bc84271f37..fe8176f62fc370d0b442683f0b727858b203d10a 100644 (file)
@@ -383,6 +383,19 @@ public:
     return IdResolver.isDeclInScope(D, Ctx, Context, S);
   }
 
+
+  void RecursiveCalcJumpScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+                               llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+                               llvm::DenseMap<Stmt*, void*>& GotoScopeMap,
+                               std::vector<void*>& ScopeStack,
+                               Stmt* CurStmt);
+
+  void RecursiveCalcLabelScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+                                llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+                                std::vector<void*>& ScopeStack,
+                                Stmt* CurStmt,
+                                Stmt* ParentCompoundStmt);
+
   /// Subroutines of ActOnDeclarator().
   TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
                                 Decl *LastDecl);
index 6dbb66a4b704e155767bfeed4eacb2fa2bca4261..8a4ffaf65de6eaafa1bc614decc5a59fa43fb2e1 100644 (file)
@@ -2496,6 +2496,79 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
   return FD;
 }
 
+static bool StatementCreatesScope(Stmt* S) {
+  bool result = false;
+  if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+    for (DeclStmt::decl_iterator i = DS->decl_begin();
+         i != DS->decl_end(); ++i) {
+      if (VarDecl* D = dyn_cast<VarDecl>(*i)) {
+        result |= D->getType()->isVariablyModifiedType();
+      }
+    }
+  }
+
+  return result;
+}
+
+void Sema::RecursiveCalcLabelScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+                                    llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+                                    std::vector<void*>& ScopeStack,
+                                    Stmt* CurStmt,
+                                    Stmt* ParentCompoundStmt) {
+  for (Stmt::child_iterator i = CurStmt->child_begin();
+       i != CurStmt->child_end(); ++i) {
+    if (!*i) continue;
+    if (StatementCreatesScope(*i))  {
+      ScopeStack.push_back(*i);
+      PopScopeMap[*i] = ParentCompoundStmt;
+    } else if (isa<LabelStmt>(CurStmt)) {
+      LabelScopeMap[CurStmt] = ScopeStack.size() ? ScopeStack.back() : 0;
+    }
+    if (isa<DeclStmt>(*i)) continue;
+    Stmt* CurCompound = isa<CompoundStmt>(*i) ? *i : ParentCompoundStmt;
+    RecursiveCalcLabelScopes(LabelScopeMap, PopScopeMap, ScopeStack,
+                             *i, CurCompound);
+  }
+
+  while (ScopeStack.size() && PopScopeMap[ScopeStack.back()] == CurStmt) {
+    ScopeStack.pop_back();
+  }
+}
+
+void Sema::RecursiveCalcJumpScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+                                   llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+                                   llvm::DenseMap<Stmt*, void*>& GotoScopeMap,
+                                   std::vector<void*>& ScopeStack,
+                                   Stmt* CurStmt) {
+  for (Stmt::child_iterator i = CurStmt->child_begin();
+       i != CurStmt->child_end(); ++i) {
+    if (!*i) continue;
+    if (StatementCreatesScope(*i))  {
+      ScopeStack.push_back(*i);
+    } else if (GotoStmt* GS = dyn_cast<GotoStmt>(*i)) {
+      void* LScope = LabelScopeMap[GS->getLabel()];
+      if (LScope) {
+        bool foundScopeInStack = false;
+        for (unsigned i = ScopeStack.size(); i > 0; --i) {
+          if (LScope == ScopeStack[i-1]) {
+            foundScopeInStack = true;
+            break;
+          }
+        }
+        if (!foundScopeInStack) {
+          Diag(GS->getSourceRange().getBegin(), diag::err_goto_into_scope);
+        }
+      }
+    }
+    if (isa<DeclStmt>(*i)) continue;
+    RecursiveCalcJumpScopes(LabelScopeMap, PopScopeMap, GotoScopeMap, ScopeStack, *i);
+  }
+
+  while (ScopeStack.size() && PopScopeMap[ScopeStack.back()] == CurStmt) {
+    ScopeStack.pop_back();
+  }
+}
+
 Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
   Decl *dcl = static_cast<Decl *>(D);
   Stmt *Body = static_cast<Stmt*>(BodyArg.release());
@@ -2511,7 +2584,8 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
   }
   PopDeclContext();
   // Verify and clean out per-function state.
-  
+
+  bool HaveLabels = !LabelMap.empty();
   // Check goto/label use.
   for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
        I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
@@ -2542,7 +2616,18 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
     }
   }
   LabelMap.clear();
-  
+
+  if (!Body) return D;
+
+  if (HaveLabels) {
+    llvm::DenseMap<Stmt*, void*> LabelScopeMap;
+    llvm::DenseMap<void*, Stmt*> PopScopeMap;
+    llvm::DenseMap<Stmt*, void*> GotoScopeMap;
+    std::vector<void*> ScopeStack;
+    RecursiveCalcLabelScopes(LabelScopeMap, PopScopeMap, ScopeStack, Body, Body);
+    RecursiveCalcJumpScopes(LabelScopeMap, PopScopeMap, GotoScopeMap, ScopeStack, Body);
+  }
+
   return D;
 }
 
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
new file mode 100644 (file)
index 0000000..0eb134c
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int test1(int x) {
+  goto L; // expected-error{{illegal jump}}
+  int a[x];
+  L:
+  return sizeof a;
+}