From 0b0f86e4c40c86750741e116690cd65b1cf49737 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 15 May 2023 11:34:46 -0400 Subject: [release-branch.go1.19] go/printer: error out of Fprint when it would write a '//line' directive with a multiline file path Line directives do not provide a way to escape newline characters, so source file paths containing newlines must not be written in them. Updates #60515. Updates #60167. Change-Id: I30f8b381cc7d1df6914c27591544edf424a4b634 Reviewed-on: https://go-review.googlesource.com/c/go/+/501578 Reviewed-by: Robert Griesemer Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot (cherry picked from commit d1087efa42ea0b0f011283a87d7a732cba51e4ad) Reviewed-on: https://go-review.googlesource.com/c/go/+/501823 Reviewed-by: Ian Lance Taylor --- src/go/printer/printer.go | 18 +++++++++++++----- src/go/printer/printer_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go index 244a19b2a7..6eda713335 100644 --- a/src/go/printer/printer.go +++ b/src/go/printer/printer.go @@ -74,10 +74,11 @@ type printer struct { // white space). If there's a difference and SourcePos is set in // ConfigMode, //line directives are used in the output to restore // original source positions for a reader. - pos token.Position // current position in AST (source) space - out token.Position // current position in output space - last token.Position // value of pos after calling writeString - linePtr *int // if set, record out.Line for the next token in *linePtr + pos token.Position // current position in AST (source) space + out token.Position // current position in output space + last token.Position // value of pos after calling writeString + linePtr *int // if set, record out.Line for the next token in *linePtr + sourcePosErr error // if non-nil, the first error emitting a //line directive // The list of all source comments, in order of appearance. comments []*ast.CommentGroup // may be nil @@ -205,6 +206,13 @@ func (p *printer) lineFor(pos token.Pos) int { // writeLineDirective writes a //line directive if necessary. func (p *printer) writeLineDirective(pos token.Position) { if pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) { + if strings.ContainsAny(pos.Filename, "\r\n") { + if p.sourcePosErr == nil { + p.sourcePosErr = fmt.Errorf("go/printer: source filename contains unexpected newline character: %q", pos.Filename) + } + return + } + p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...) p.output = append(p.output, tabwriter.Escape) @@ -1178,7 +1186,7 @@ func (p *printer) printNode(node any) error { goto unsupported } - return nil + return p.sourcePosErr unsupported: return fmt.Errorf("go/printer: unsupported node type %T", node) diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index cb62b3e4f3..3a8ce60431 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -797,3 +797,31 @@ func f() { t.Fatalf("got %q, want %q", got, want) } } + +func TestSourcePosNewline(t *testing.T) { + // We don't provide a syntax for escaping or unescaping characters in line + // directives (see https://go.dev/issue/24183#issuecomment-372449628). + // As a result, we cannot write a line directive with the correct path for a + // filename containing newlines. We should return an error rather than + // silently dropping or mangling it. + + fname := "foo\nbar/bar.go" + src := `package bar` + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors|parser.SkipObjectResolution) + if err != nil { + t.Fatal(err) + } + + cfg := &Config{ + Mode: SourcePos, // emit line comments + Tabwidth: 8, + } + var buf bytes.Buffer + if err := cfg.Fprint(&buf, fset, f); err == nil { + t.Errorf("Fprint did not error for source file path containing newline") + } + if buf.Len() != 0 { + t.Errorf("unexpected Fprint output:\n%s", buf.Bytes()) + } +} -- cgit v1.2.3-54-g00ecf