Skip to content

Commit 9d23975

Browse files
author
Bryan C. Mills
committed
cmd/go/internal/modload: ensure that __debug_modinfo__ is not discarded during linking
Fixes #28753 Updates #29628 Change-Id: I4a561be7d491a0d088e656b00151ae1bdbd16a84 Reviewed-on: https://go-review.googlesource.com/c/158357 Run-TryBot: Bryan C. Mills <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent 193c16a commit 9d23975

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

src/cmd/go/internal/modload/build.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,19 @@ func findModule(target, path string) module.Version {
252252
func ModInfoProg(info string) []byte {
253253
// Inject a variable with the debug information as runtime/debug.modinfo,
254254
// but compile it in package main so that it is specific to the binary.
255-
// No need to populate it in an init func; it will still work with go:linkname.
255+
//
256+
// The variable must be a literal so that it will have the correct value
257+
// before the initializer for package main runs.
258+
//
259+
// We also want the value to be present even if runtime/debug.modinfo is
260+
// otherwise unused in the rest of the program. Reading it in an init function
261+
// suffices for now.
262+
256263
return []byte(fmt.Sprintf(`package main
257264
import _ "unsafe"
258265
//go:linkname __debug_modinfo__ runtime/debug.modinfo
259266
var __debug_modinfo__ = %q
267+
var keepalive_modinfo = __debug_modinfo__
268+
func init() { keepalive_modinfo = __debug_modinfo__ }
260269
`, string(infoStart)+info+string(infoEnd)))
261270
}

src/cmd/go/testdata/script/mod_modinfo.txt

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,83 @@ cd x
77
go mod edit -require=rsc.io/[email protected]
88
go mod edit -replace=rsc.io/[email protected]=rsc.io/[email protected]
99

10-
go run main.go
11-
12-
stderr 'Hello, world.'
10+
# Build a binary and ensure that it can output its own debug info.
11+
# The debug info should be accessible before main starts (golang.org/issue/29628).
12+
go build
13+
exec ./x$GOEXE
1314
stderr 'mod\s+x\s+\(devel\)'
1415
stderr 'dep\s+rsc.io/quote\s+v1.5.2\s+'
1516
stderr '=>\s+rsc.io/quote\s+v1.0.0\s+h1:'
17+
stderr 'Hello, world.'
18+
19+
[short] skip
20+
21+
# Build a binary that accesses its debug info by reading the binary directly
22+
# (rather than through debug.ReadBuildInfo).
23+
# The debug info should still be present (golang.org/issue/28753).
24+
cd unused
25+
go build
26+
exec ./unused$GOEXE
1627

1728
-- x/go.mod --
1829
module x
1930

31+
-- x/lib/lib.go --
32+
// Package lib accesses runtime/debug.modinfo before package main's init
33+
// functions have run.
34+
package lib
35+
36+
import "runtime/debug"
37+
38+
func init() {
39+
m, ok := debug.ReadBuildInfo()
40+
if !ok {
41+
panic("failed debug.ReadBuildInfo")
42+
}
43+
println("mod", m.Main.Path, m.Main.Version)
44+
for _, d := range m.Deps {
45+
println("dep", d.Path, d.Version, d.Sum)
46+
if r := d.Replace; r != nil {
47+
println("=>", r.Path, r.Version, r.Sum)
48+
}
49+
}
50+
}
51+
2052
-- x/main.go --
2153
package main
2254

23-
import "runtime/debug"
24-
import "rsc.io/quote"
55+
import (
56+
"rsc.io/quote"
57+
_ "x/lib"
58+
)
2559

2660
func main() {
27-
println(quote.Hello())
28-
29-
m, ok := debug.ReadBuildInfo()
30-
if !ok {
31-
panic("failed debug.ReadBuildInfo")
32-
}
33-
println("mod", m.Main.Path, m.Main.Version)
34-
for _, d := range m.Deps {
35-
println("dep", d.Path, d.Version, d.Sum)
36-
if r := d.Replace; r != nil {
37-
println("=>", r.Path, r.Version, r.Sum)
38-
}
39-
}
61+
println(quote.Hello())
62+
}
63+
64+
-- x/unused/main.go --
65+
// The unused binary does not access runtime/debug.modinfo.
66+
package main
67+
68+
import (
69+
"bytes"
70+
"encoding/hex"
71+
"io/ioutil"
72+
"log"
73+
"os"
74+
75+
_ "rsc.io/quote"
76+
)
77+
78+
func main() {
79+
b, err := ioutil.ReadFile(os.Args[0])
80+
if err != nil {
81+
log.Fatal(err)
82+
}
83+
84+
infoStart, _ := hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
85+
if !bytes.Contains(b, infoStart) {
86+
log.Fatal("infoStart not found in binary")
87+
}
88+
log.Println("ok")
4089
}

0 commit comments

Comments
 (0)