aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2014-04-17 11:47:12 -0700
committerIan Lance Taylor <iant@golang.org>2014-04-17 11:47:12 -0700
commit6524310770649b6aa9786711edd2f6eeab4ba61a (patch)
tree5a8705542257d708e6c1747c3fe777311e44730d
parented88076c6437fa87c26a568b46020eacc9202e13 (diff)
downloadgo-6524310770649b6aa9786711edd2f6eeab4ba61a.tar.gz
go-6524310770649b6aa9786711edd2f6eeab4ba61a.zip
cmd/pack: handle very long lines in pkgdef
LGTM=rsc, bradfitz R=golang-codereviews, rsc, bradfitz CC=golang-codereviews https://golang.org/cl/88170049
-rw-r--r--src/cmd/pack/pack.go20
-rw-r--r--src/cmd/pack/pack_test.go102
2 files changed, 98 insertions, 24 deletions
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index 468104deb6..594433712d 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -406,20 +406,22 @@ func readPkgdef(file string) (data []byte, err error) {
// Read from file, collecting header for __.PKGDEF.
// The header is from the beginning of the file until a line
// containing just "!". The first line must begin with "go object ".
- var buf bytes.Buffer
- scan := bufio.NewScanner(f)
- for scan.Scan() {
- line := scan.Text()
- if buf.Len() == 0 && !strings.HasPrefix(line, "go object ") {
+ rbuf := bufio.NewReader(f)
+ var wbuf bytes.Buffer
+ for {
+ line, err := rbuf.ReadBytes('\n')
+ if err != nil {
+ return nil, err
+ }
+ if wbuf.Len() == 0 && !bytes.HasPrefix(line, []byte("go object ")) {
return nil, errors.New("not a Go object file")
}
- if line == "!" {
+ if bytes.Equal(line, []byte("!\n")) {
break
}
- buf.WriteString(line)
- buf.WriteString("\n")
+ wbuf.Write(line)
}
- return buf.Bytes(), nil
+ return wbuf.Bytes(), nil
}
// exactly16Bytes truncates the string if necessary so it is at most 16 bytes long,
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index 9389349187..bd4b224aff 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -198,17 +198,97 @@ func TestHello(t *testing.T) {
t.Fatal(err)
}
+ char := findChar(t, dir)
+
run := func(args ...string) string {
- cmd := exec.Command(args[0], args[1:]...)
- cmd.Dir = dir
- out, err := cmd.CombinedOutput()
+ return doRun(t, dir, args...)
+ }
+
+ run("go", "build", "cmd/pack") // writes pack binary to dir
+ run("go", "tool", char+"g", "hello.go")
+ run("./pack", "grc", "hello.a", "hello."+char)
+ run("go", "tool", char+"l", "-o", "a.out", "hello.a")
+ out := run("./a.out")
+ if out != "hello world\n" {
+ t.Fatal("incorrect output: %q, want %q", out, "hello world\n")
+ }
+}
+
+// Test that pack works with very long lines in PKGDEF.
+func TestLargeDefs(t *testing.T) {
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ large := filepath.Join(dir, "large.go")
+ f, err := os.Create(large)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ printf := func(format string, args ...interface{}) {
+ _, err := fmt.Fprintf(f, format, args...)
if err != nil {
- t.Fatalf("%v: %v\n%s", args, err, string(out))
+ t.Fatalf("Writing to %s: %v", large, err)
}
- return string(out)
}
- out := run("go", "env")
+ printf("package large\n\ntype T struct {\n")
+ for i := 0; i < 10000; i++ {
+ printf("f%d int `tag:\"", i)
+ for j := 0; j < 100; j++ {
+ printf("t%d=%d,", j, j)
+ }
+ printf("\"`\n")
+ }
+ printf("}\n")
+ if err = f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ main := filepath.Join(dir, "main.go")
+ prog := `
+ package main
+ import "./large"
+ var V large.T
+ func main() {
+ println("ok")
+ }
+ `
+ err = ioutil.WriteFile(main, []byte(prog), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ char := findChar(t, dir)
+
+ run := func(args ...string) string {
+ return doRun(t, dir, args...)
+ }
+
+ run("go", "build", "cmd/pack") // writes pack binary to dir
+ run("go", "tool", char+"g", "large.go")
+ run("./pack", "grc", "large.a", "large."+char)
+ run("go", "tool", char+"g", "main.go")
+ run("go", "tool", char+"l", "-o", "a.out", "main."+char)
+ out := run("./a.out")
+ if out != "ok\n" {
+ t.Fatal("incorrect output: %q, want %q", out, "ok\n")
+ }
+}
+
+// doRun runs a program in a directory and returns the output.
+func doRun(t *testing.T, dir string, args ...string) string {
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%v: %v\n%s", args, err, string(out))
+ }
+ return string(out)
+}
+
+// findChar returns the architecture character for the go command.
+func findChar(t *testing.T, dir string) string {
+ out := doRun(t, dir, "go", "env")
re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
if err != nil {
t.Fatal(err)
@@ -217,15 +297,7 @@ func TestHello(t *testing.T) {
if fields == nil {
t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
}
- char := fields[1]
- run("go", "build", "cmd/pack") // writes pack binary to dir
- run("go", "tool", char+"g", "hello.go")
- run("./pack", "grc", "hello.a", "hello."+char)
- run("go", "tool", char+"l", "-o", "a.out", "hello.a")
- out = run("./a.out")
- if out != "hello world\n" {
- t.Fatal("incorrect output: %q, want %q", out, "hello world\n")
- }
+ return fields[1]
}
// Fake implementation of files.