From 7a26d9fcedd94a1ba0d95833b0cdbbdcc776fe19 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 31 Oct 2016 16:58:15 -0700 Subject: [PATCH] cmd/compile/internal/syntax: don't panic if no error handler is provided If no error handler is provided, terminate parsing with first error and report that error. Fixes #17697. Change-Id: I9070faf7239bd53725de141507912b92ded3474b Reviewed-on: https://go-review.googlesource.com/32456 Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/syntax/parser.go | 4 +++- .../compile/internal/syntax/parser_test.go | 7 ++++++ src/cmd/compile/internal/syntax/syntax.go | 24 +++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index fcf4f5b692..1ed20651b1 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -28,6 +28,8 @@ type parser struct { nerrors int // error count } +type parserError string // for error recovery if no error handler was installed + func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { p.scanner.init(src, func(pos, line int, msg string) { p.nerrors++ @@ -35,7 +37,7 @@ func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { errh(pos, line, msg) return } - panic(fmt.Sprintf("%d: %s\n", line, msg)) + panic(parserError(fmt.Sprintf("%d: %s\n", line, msg))) }, pragh) p.fnest = 0 diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go index 8e6b77d0c6..780f10835c 100644 --- a/src/cmd/compile/internal/syntax/parser_test.go +++ b/src/cmd/compile/internal/syntax/parser_test.go @@ -155,3 +155,10 @@ func verifyPrint(filename string, ast1 *File) { panic("not equal") } } + +func TestIssue17697(t *testing.T) { + _, err := ReadBytes(nil, nil, nil, 0) // return with parser error, don't panic + if err == nil { + t.Errorf("no error reported") + } +} diff --git a/src/cmd/compile/internal/syntax/syntax.go b/src/cmd/compile/internal/syntax/syntax.go index 49831d0fbd..71fc097c3b 100644 --- a/src/cmd/compile/internal/syntax/syntax.go +++ b/src/cmd/compile/internal/syntax/syntax.go @@ -5,6 +5,7 @@ package syntax import ( + "errors" "fmt" "io" "os" @@ -52,18 +53,31 @@ func ReadBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (* return Read(&bytesReader{src}, errh, pragh, mode) } -func Read(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) { +func Read(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (ast *File, err error) { + defer func() { + if p := recover(); p != nil { + if msg, ok := p.(parserError); ok { + err = errors.New(string(msg)) + return + } + panic(p) + } + }() + var p parser p.init(src, errh, pragh) - p.next() - ast := p.file() + ast = p.file() + // TODO(gri) This isn't quite right: Even if there's an error handler installed + // we should report an error if parsing found syntax errors. This also + // requires updating the noder's ReadFile call. if errh == nil && p.nerrors > 0 { - return nil, fmt.Errorf("%d syntax errors", p.nerrors) + ast = nil + err = fmt.Errorf("%d syntax errors", p.nerrors) } - return ast, nil + return } func Write(w io.Writer, n *File) error { -- 2.48.1