]> Cypherpunks repositories - gostls13.git/commitdiff
asm: handle EOF better
authorRob Pike <r@golang.org>
Thu, 17 Sep 2015 20:46:46 +0000 (13:46 -0700)
committerRob Pike <r@golang.org>
Fri, 18 Sep 2015 18:09:15 +0000 (18:09 +0000)
Add some error catches to prevent looping at EOF.
Also give better diagnostics.
Also add tests for these cases.

Fixes #12656.

Change-Id: I1355fc149b71c868e740bfa53de29c25d160777d
Reviewed-on: https://go-review.googlesource.com/14710
Reviewed-by: Andrew Gerrand <adg@golang.org>
src/cmd/asm/internal/lex/input.go
src/cmd/asm/internal/lex/lex_test.go

index cd9168064ddf564de8b2d20df014ec5615e90a24..e5a33013e17d2c35254b9863f7b4466f1947020f 100644 (file)
@@ -63,7 +63,12 @@ func predefine(defines flags.MultiFlag) map[string]*Macro {
        return macros
 }
 
+var panicOnError bool // For testing.
+
 func (in *Input) Error(args ...interface{}) {
+       if panicOnError {
+               panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
+       }
        fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
        os.Exit(1)
 }
@@ -113,6 +118,10 @@ func (in *Input) Next() ScanToken {
                        }
                        fallthrough
                default:
+                       if tok == scanner.EOF && len(in.ifdefStack) > 0 {
+                               // We're skipping text but have run out of input with no #endif.
+                               in.Error("unclosed #ifdef or #ifndef")
+                       }
                        in.beginningOfLine = tok == '\n'
                        if in.enabled() {
                                in.text = in.Stack.Text()
@@ -251,6 +260,9 @@ func (in *Input) macroDefinition(name string) ([]string, []Token) {
        var tokens []Token
        // Scan to newline. Backslashes escape newlines.
        for tok != '\n' {
+               if tok == scanner.EOF {
+                       in.Error("missing newline in macro definition for %q\n", name)
+               }
                if tok == '\\' {
                        tok = in.Stack.Next()
                        if tok != '\n' && tok != '\\' {
index 32cc13ea6611116f1e5e023c0160535cebae87c1..14ffffecc812d2b38d2c5a04d9cbda8e8cf52c97 100644 (file)
@@ -258,3 +258,76 @@ func drain(input *Input) string {
                buf.WriteString(input.Text())
        }
 }
+
+type badLexTest struct {
+       input string
+       error string
+}
+
+var badLexTests = []badLexTest{
+       {
+               "3 #define foo bar\n",
+               "'#' must be first item on line",
+       },
+       {
+               "#ifdef foo\nhello",
+               "unclosed #ifdef or #ifndef",
+       },
+       {
+               "#ifndef foo\nhello",
+               "unclosed #ifdef or #ifndef",
+       },
+       {
+               "#ifdef foo\nhello\n#else\nbye",
+               "unclosed #ifdef or #ifndef",
+       },
+       {
+               "#define A() A()\nA()",
+               "recursive macro invocation",
+       },
+       {
+               "#define A a\n#define A a\n",
+               "redefinition of macro",
+       },
+       {
+               "#define A a",
+               "no newline after macro definition",
+       },
+}
+
+func TestBadLex(t *testing.T) {
+       for _, test := range badLexTests {
+               input := NewInput(test.error)
+               input.Push(NewTokenizer(test.error, strings.NewReader(test.input), nil))
+               err := firstError(input)
+               if err == nil {
+                       t.Errorf("%s: got no error", test.error)
+                       continue
+               }
+               if !strings.Contains(err.Error(), test.error) {
+                       t.Errorf("got error %q expected %q", err.Error(), test.error)
+               }
+       }
+}
+
+// firstError returns the first error value triggered by the input.
+func firstError(input *Input) (err error) {
+       panicOnError = true
+       defer func() {
+               panicOnError = false
+               switch e := recover(); e := e.(type) {
+               case nil:
+               case error:
+                       err = e
+               default:
+                       panic(e)
+               }
+       }()
+
+       for {
+               tok := input.Next()
+               if tok == scanner.EOF {
+                       return
+               }
+       }
+}