From 49594244d388401a2cec34ab22d28f4e66d46de1 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 15 May 2023 11:49:56 -0400 Subject: [PATCH] [release-branch.go1.20] cmd/cover: error out if a requested source file contains a newline cmd/cover uses '//line' directives to map instrumented source files back to the original source file and line numbers. Line directives have no way to escape newline characters, so cmd/cover must not be used with source file paths that contain such characters. Updates #60516. Updates #60167. Change-Id: I6dc039392d59fc3a5a6121ef6ca97b0ab0da5288 Reviewed-on: https://go-review.googlesource.com/c/go/+/501577 Auto-Submit: Bryan Mills Run-TryBot: Bryan Mills Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot (cherry picked from commit 3d78c735fc7d213e23383b9744297bd5251dc0e3) Reviewed-on: https://go-review.googlesource.com/c/go/+/501818 Auto-Submit: Dmitri Shuralyov --- src/cmd/cover/cover.go | 10 ++++++++++ src/cmd/cover/cover_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go index 74bb500cb9..5fd8b95272 100644 --- a/src/cmd/cover/cover.go +++ b/src/cmd/cover/cover.go @@ -568,6 +568,11 @@ func annotate(names []string) { } // TODO: process files in parallel here if it matters. for k, name := range names { + if strings.ContainsAny(name, "\r\n") { + // annotateFile uses '//line' directives, which don't permit newlines. + log.Fatalf("cover: input path contains newline character: %q", name) + } + last := false if k == len(names)-1 { last = true @@ -645,6 +650,11 @@ func (p *Package) annotateFile(name string, fd io.Writer, last bool) { } newContent := file.edit.Bytes() + if strings.ContainsAny(name, "\r\n") { + // This should have been checked by the caller already, but we double check + // here just to be sure we haven't missed a caller somewhere. + panic(fmt.Sprintf("annotateFile: name contains unexpected newline character: %q", name)) + } fmt.Fprintf(fd, "//line %s:1:1\n", name) fd.Write(newContent) diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index af266b5e83..6ed4ae4675 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -574,3 +574,34 @@ func runExpectingError(c *exec.Cmd, t *testing.T) string { } return string(out) } + +func TestSrcPathWithNewline(t *testing.T) { + testenv.MustHaveExec(t) + t.Parallel() + + // srcPath is intentionally not clean so that the path passed to testcover + // will not normalize the trailing / to a \ on Windows. + srcPath := t.TempDir() + string(filepath.Separator) + "\npackage main\nfunc main() { panic(string([]rune{'u', 'h', '-', 'o', 'h'}))\n/*/main.go" + mainSrc := ` package main + +func main() { + /* nothing here */ + println("ok") +} +` + if err := os.MkdirAll(filepath.Dir(srcPath), 0777); err != nil { + t.Skipf("creating directory with bogus path: %v", err) + } + if err := os.WriteFile(srcPath, []byte(mainSrc), 0666); err != nil { + t.Skipf("writing file with bogus directory: %v", err) + } + + cmd := testenv.Command(t, testcover(t), "-mode=atomic", srcPath) + cmd.Stderr = new(bytes.Buffer) + out, err := cmd.Output() + t.Logf("%v:\n%s", cmd, out) + t.Logf("stderr:\n%s", cmd.Stderr) + if err == nil { + t.Errorf("unexpected success; want failure due to newline in file path") + } +} -- 2.48.1