From 31c10a12c85e39e01602378e75e5ef484e5a8330 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 21 Oct 2022 14:36:04 -0700 Subject: [PATCH] Fix panic in parser when first token is invalid newParser was calling p.next(), which could trigger a scanner error that results in a panic. Move the first p.next() into parse(p), which correctly converts the paanic into a reportable error. Bug: 254831383 Test: TestParserError Change-Id: I2a427010379bb8dd5087550c7f159499cbb84066 --- parser/parser.go | 3 ++- parser/parser_test.go | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/parser/parser.go b/parser/parser.go index df694c5..63a6ac1 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -70,6 +70,7 @@ func parse(p *parser) (file *File, errs []error) { } }() + p.next() defs := p.parseDefinitions() p.accept(scanner.EOF) errs = p.errors @@ -100,6 +101,7 @@ func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error func ParseExpression(r io.Reader) (value Expression, errs []error) { p := newParser(r, NewScope(nil)) + p.next() value = p.parseExpression() p.accept(scanner.EOF) errs = p.errors @@ -124,7 +126,6 @@ func newParser(r io.Reader, scope *Scope) *parser { } p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanComments - p.next() return p } diff --git a/parser/parser_test.go b/parser/parser_test.go index 4cc4e1b..b393792 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -1139,7 +1139,7 @@ var validParseTestCases = []struct { Comments: []*Comment{ &Comment{ Comment: []string{"/* comment3", " comment4 */"}, - Slash: mkpos(32, 5, 3), + Slash: mkpos(32, 5, 3), }, &Comment{ Comment: []string{"// comment5"}, @@ -1214,7 +1214,36 @@ func TestParseValidInput(t *testing.T) { } } -// TODO: Test error strings +func TestParserError(t *testing.T) { + testcases := []struct { + name string + input string + err string + }{ + { + name: "invalid first token", + input: "\x00", + err: "invalid character NUL", + }, + // TODO: test more parser errors + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + r := bytes.NewBufferString(tt.input) + _, errs := ParseAndEval("", r, NewScope(nil)) + if len(errs) == 0 { + t.Fatalf("missing expected error") + } + if g, w := errs[0], tt.err; !strings.Contains(g.Error(), w) { + t.Errorf("expected error %q, got %q", w, g) + } + for _, err := range errs[1:] { + t.Errorf("got unexpected extra error %q", err) + } + }) + } +} func TestParserEndPos(t *testing.T) { in := `