Skip to content

Commit

Permalink
asm: handle EOF better
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
robpike committed Sep 18, 2015
1 parent 49580db commit 49065cb
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/cmd/asm/internal/lex/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 != '\\' {
Expand Down
73 changes: 73 additions & 0 deletions src/cmd/asm/internal/lex/lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}

0 comments on commit 49065cb

Please sign in to comment.