Skip to content

Commit 7ee3f14

Browse files
committed
runtime: disable GC during debug call tests
Currently the debug call protocol implementation we use for testing is riddled with write barriers, and called from a signal handler. This is not safe, as write barriers need a P to execute. Ideally this implementation would be rewritten to avoid the write barriers, but it's not straightforward, and needs some thought. As a temporary measure, disable GC during the debug call tests to avoid a write barrier. Note that this does not indicate a problem with real use of the debug call protocol. Only our test implementation has this issue, because it needs to get executed in a signal handler, normally a separate process is interfacing with the protocol via process signals and ptrace (and the like). Fixes #49370. Change-Id: Ic0fde5d0f4c64f9ecc9789b7dabb3954538fe0a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/361896 Trust: Michael Knyszek <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent 759eaa2 commit 7ee3f14

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

src/runtime/debug_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ func skipUnderDebugger(t *testing.T) {
114114
}
115115

116116
func TestDebugCall(t *testing.T) {
117+
// InjectDebugCall cannot be executed while a GC is actively in
118+
// progress. Wait until the current GC is done, and turn it off.
119+
//
120+
// See #49370.
121+
runtime.GC()
122+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
123+
117124
g, after := startDebugCallWorker(t)
118125
defer after()
119126

@@ -143,6 +150,7 @@ func TestDebugCall(t *testing.T) {
143150
x1: 42.0,
144151
}
145152
}
153+
146154
if _, err := runtime.InjectDebugCall(g, fn, &regs, args, debugCallTKill, false); err != nil {
147155
t.Fatal(err)
148156
}
@@ -164,6 +172,13 @@ func TestDebugCall(t *testing.T) {
164172
}
165173

166174
func TestDebugCallLarge(t *testing.T) {
175+
// InjectDebugCall cannot be executed while a GC is actively in
176+
// progress. Wait until the current GC is done, and turn it off.
177+
//
178+
// See #49370.
179+
runtime.GC()
180+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
181+
167182
g, after := startDebugCallWorker(t)
168183
defer after()
169184

@@ -193,6 +208,13 @@ func TestDebugCallLarge(t *testing.T) {
193208
}
194209

195210
func TestDebugCallGC(t *testing.T) {
211+
// InjectDebugCall cannot be executed while a GC is actively in
212+
// progress. Wait until the current GC is done, and turn it off.
213+
//
214+
// See #49370.
215+
runtime.GC()
216+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
217+
196218
g, after := startDebugCallWorker(t)
197219
defer after()
198220

@@ -203,6 +225,13 @@ func TestDebugCallGC(t *testing.T) {
203225
}
204226

205227
func TestDebugCallGrowStack(t *testing.T) {
228+
// InjectDebugCall cannot be executed while a GC is actively in
229+
// progress. Wait until the current GC is done, and turn it off.
230+
//
231+
// See #49370.
232+
runtime.GC()
233+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
234+
206235
g, after := startDebugCallWorker(t)
207236
defer after()
208237

@@ -233,6 +262,12 @@ func TestDebugCallUnsafePoint(t *testing.T) {
233262
// This can deadlock if there aren't enough threads or if a GC
234263
// tries to interrupt an atomic loop (see issue #10958).
235264
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
265+
266+
// InjectDebugCall cannot be executed while a GC is actively in
267+
// progress. Wait until the current GC is done, and turn it off.
268+
//
269+
// See #49370.
270+
runtime.GC()
236271
defer debug.SetGCPercent(debug.SetGCPercent(-1))
237272

238273
// Test that the runtime refuses call injection at unsafe points.
@@ -256,6 +291,13 @@ func TestDebugCallPanic(t *testing.T) {
256291
// This can deadlock if there aren't enough threads.
257292
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
258293

294+
// InjectDebugCall cannot be executed while a GC is actively in
295+
// progress. Wait until the current GC is done, and turn it off.
296+
//
297+
// See #49370.
298+
runtime.GC()
299+
defer debug.SetGCPercent(debug.SetGCPercent(-1))
300+
259301
ready := make(chan *runtime.G)
260302
var stop uint32
261303
defer atomic.StoreUint32(&stop, 1)

src/runtime/export_debug_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ type debugCallHandler struct {
107107
}
108108

109109
func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
110+
// TODO(49370): This code is riddled with write barriers, but called from
111+
// a signal handler. Add the go:nowritebarrierrec annotation and restructure
112+
// this to avoid write barriers.
113+
110114
switch h.gp.atomicstatus {
111115
case _Grunning:
112116
if getg().m != h.mp {
@@ -141,7 +145,11 @@ func (h *debugCallHandler) inject(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
141145
}
142146

143147
func (h *debugCallHandler) handle(info *siginfo, ctxt *sigctxt, gp2 *g) bool {
144-
// Sanity check.
148+
// TODO(49370): This code is riddled with write barriers, but called from
149+
// a signal handler. Add the go:nowritebarrierrec annotation and restructure
150+
// this to avoid write barriers.
151+
152+
// Double-check m.
145153
if getg().m != h.mp {
146154
println("trap on wrong M", getg().m, h.mp)
147155
return false

0 commit comments

Comments
 (0)