Skip to content

Commit eafe9a1

Browse files
committed
cmd/compile: hide init functions in tracebacks
Treat compiler-generated init functions as wrappers, so they will not be shown in tracebacks. The exception to this rule is that we'd like to show the line number of initializers for global variables in tracebacks. In order to preserve line numbers for those cases, separate out the code for those initializers into a separate function (which is not marked as autogenerated). This CL makes the go binary 0.2% bigger. Fixes #29919 Change-Id: I0f1fbfc03d10d764ce3a8ddb48fb387ca8453386 Reviewed-on: https://go-review.googlesource.com/c/159717 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent d585f04 commit eafe9a1

File tree

5 files changed

+125
-3
lines changed

5 files changed

+125
-3
lines changed

src/cmd/compile/internal/gc/init.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ func anyinit(n []*Node) bool {
5757

5858
// fninit hand-crafts package initialization code.
5959
//
60+
// func init.ializers() { (0)
61+
// <init stmts>
62+
// }
6063
// var initdone· uint8 (1)
6164
// func init() { (2)
6265
// if initdone· > 1 { (3)
@@ -68,7 +71,7 @@ func anyinit(n []*Node) bool {
6871
// initdone· = 1 (5)
6972
// // over all matching imported symbols
7073
// <pkg>.init() (6)
71-
// { <init stmts> } (7)
74+
// init.ializers() (7)
7275
// init.<n>() // if any (8)
7376
// initdone· = 2 (9)
7477
// return (10)
@@ -80,6 +83,27 @@ func fninit(n []*Node) {
8083
return
8184
}
8285

86+
// (0)
87+
// Make a function that contains all the initialization statements.
88+
// This is a separate function because we want it to appear in
89+
// stack traces, where the init function itself does not.
90+
var initializers *types.Sym
91+
if len(nf) > 0 {
92+
lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
93+
initializers = lookup("init.ializers")
94+
disableExport(initializers)
95+
fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
96+
fn.Nbody.Set(nf)
97+
funcbody()
98+
99+
fn = typecheck(fn, ctxStmt)
100+
Curfn = fn
101+
typecheckslice(nf, ctxStmt)
102+
Curfn = nil
103+
funccompile(fn)
104+
lineno = autogeneratedPos
105+
}
106+
83107
var r []*Node
84108

85109
// (1)
@@ -130,7 +154,11 @@ func fninit(n []*Node) {
130154
}
131155

132156
// (7)
133-
r = append(r, nf...)
157+
if initializers != nil {
158+
n := newname(initializers)
159+
addvar(n, functype(nil, nil, nil), PFUNC)
160+
r = append(r, nod(OCALL, n, nil))
161+
}
134162

135163
// (8)
136164

src/cmd/internal/objabi/funcid.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func GetFuncID(name, file string) FuncID {
8383
case "runtime.panicwrap":
8484
return FuncID_panicwrap
8585
}
86-
if file == "<autogenerated>" && !strings.HasSuffix(name, ".init") {
86+
if file == "<autogenerated>" {
8787
return FuncID_wrapper
8888
}
8989
if strings.HasPrefix(name, "runtime.call") {

test/fixedbugs/issue29919.dir/a.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Make sure tracebacks from initialization code are reported correctly.
6+
7+
package a
8+
9+
import (
10+
"fmt"
11+
"runtime"
12+
"strings"
13+
)
14+
15+
var x = f() // line 15
16+
17+
func f() int {
18+
var b [4096]byte
19+
n := runtime.Stack(b[:], false) // line 19
20+
s := string(b[:n])
21+
var pcs [10]uintptr
22+
n = runtime.Callers(1, pcs[:]) // line 22
23+
24+
// Check the Stack results.
25+
if debug {
26+
println(s)
27+
}
28+
if strings.Contains(s, "autogenerated") {
29+
panic("autogenerated code in traceback")
30+
}
31+
if !strings.Contains(s, "a.go:15") {
32+
panic("missing a.go:15")
33+
}
34+
if !strings.Contains(s, "a.go:19") {
35+
panic("missing a.go:19")
36+
}
37+
if !strings.Contains(s, "a.init.ializers") {
38+
panic("missing a.init.ializers")
39+
}
40+
41+
// Check the CallersFrames results.
42+
if debug {
43+
iter := runtime.CallersFrames(pcs[:n])
44+
for {
45+
f, more := iter.Next()
46+
fmt.Printf("%s %s:%d\n", f.Function, f.File, f.Line)
47+
if !more {
48+
break
49+
}
50+
}
51+
}
52+
iter := runtime.CallersFrames(pcs[:n])
53+
f, more := iter.Next()
54+
if f.Function != "a.f" || !strings.HasSuffix(f.File, "a.go") || f.Line != 22 {
55+
panic(fmt.Sprintf("bad f %v\n", f))
56+
}
57+
if !more {
58+
panic("traceback truncated after f")
59+
}
60+
f, more = iter.Next()
61+
if f.Function != "a.init.ializers" || !strings.HasSuffix(f.File, "a.go") || f.Line != 15 {
62+
panic(fmt.Sprintf("bad init.ializers %v\n", f))
63+
}
64+
if !more {
65+
panic("traceback truncated after init.ializers")
66+
}
67+
f, _ = iter.Next()
68+
if f.Function != "runtime.main" {
69+
panic("runtime.main missing")
70+
}
71+
72+
return 0
73+
}
74+
75+
const debug = false

test/fixedbugs/issue29919.dir/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import _ "./a"
8+
9+
func main() {
10+
}

test/fixedbugs/issue29919.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// rundir
2+
3+
// Copyright 2019 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// Make sure tracebacks from initialization code are reported correctly.
8+
9+
package ignored

0 commit comments

Comments
 (0)