Skip to content

Commit 0b0f86e

Browse files
Bryan C. Millsprattmic
Bryan C. Mills
authored andcommitted
[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 <[email protected]> Auto-Submit: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> (cherry picked from commit d1087efa42ea0b0f011283a87d7a732cba51e4ad) Reviewed-on: https://go-review.googlesource.com/c/go/+/501823 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 6d44c15 commit 0b0f86e

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

src/go/printer/printer.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ type printer struct {
7474
// white space). If there's a difference and SourcePos is set in
7575
// ConfigMode, //line directives are used in the output to restore
7676
// original source positions for a reader.
77-
pos token.Position // current position in AST (source) space
78-
out token.Position // current position in output space
79-
last token.Position // value of pos after calling writeString
80-
linePtr *int // if set, record out.Line for the next token in *linePtr
77+
pos token.Position // current position in AST (source) space
78+
out token.Position // current position in output space
79+
last token.Position // value of pos after calling writeString
80+
linePtr *int // if set, record out.Line for the next token in *linePtr
81+
sourcePosErr error // if non-nil, the first error emitting a //line directive
8182

8283
// The list of all source comments, in order of appearance.
8384
comments []*ast.CommentGroup // may be nil
@@ -205,6 +206,13 @@ func (p *printer) lineFor(pos token.Pos) int {
205206
// writeLineDirective writes a //line directive if necessary.
206207
func (p *printer) writeLineDirective(pos token.Position) {
207208
if pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
209+
if strings.ContainsAny(pos.Filename, "\r\n") {
210+
if p.sourcePosErr == nil {
211+
p.sourcePosErr = fmt.Errorf("go/printer: source filename contains unexpected newline character: %q", pos.Filename)
212+
}
213+
return
214+
}
215+
208216
p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation
209217
p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...)
210218
p.output = append(p.output, tabwriter.Escape)
@@ -1178,7 +1186,7 @@ func (p *printer) printNode(node any) error {
11781186
goto unsupported
11791187
}
11801188

1181-
return nil
1189+
return p.sourcePosErr
11821190

11831191
unsupported:
11841192
return fmt.Errorf("go/printer: unsupported node type %T", node)

src/go/printer/printer_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,31 @@ func f() {
797797
t.Fatalf("got %q, want %q", got, want)
798798
}
799799
}
800+
801+
func TestSourcePosNewline(t *testing.T) {
802+
// We don't provide a syntax for escaping or unescaping characters in line
803+
// directives (see https://go.dev/issue/24183#issuecomment-372449628).
804+
// As a result, we cannot write a line directive with the correct path for a
805+
// filename containing newlines. We should return an error rather than
806+
// silently dropping or mangling it.
807+
808+
fname := "foo\nbar/bar.go"
809+
src := `package bar`
810+
fset := token.NewFileSet()
811+
f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors|parser.SkipObjectResolution)
812+
if err != nil {
813+
t.Fatal(err)
814+
}
815+
816+
cfg := &Config{
817+
Mode: SourcePos, // emit line comments
818+
Tabwidth: 8,
819+
}
820+
var buf bytes.Buffer
821+
if err := cfg.Fprint(&buf, fset, f); err == nil {
822+
t.Errorf("Fprint did not error for source file path containing newline")
823+
}
824+
if buf.Len() != 0 {
825+
t.Errorf("unexpected Fprint output:\n%s", buf.Bytes())
826+
}
827+
}

0 commit comments

Comments
 (0)