Skip to content

Commit f0ee7c6

Browse files
zx2c4mknyszek
authored andcommitted
[release-branch.go1.17] runtime: keep //go:cgo_unsafe_args arguments alive to prevent GC
When syscall's DLL.FindProc calls into syscall_getprocaddress with a byte slice pointer, we need to keep those bytes alive. Otherwise the GC will collect the allocation, and we wind up calling `GetProcAddress` on garbage, which showed up as various flakes in the builders. It turns out that this problem extends to many uses of //go:cgo_unsafe_args throughout, on all platforms. So this patch fixes the issue by keeping non-integer pointer arguments alive through their invocation in //go:cgo_unsafe_args functions. Fixes #49868. Updates #49731. Change-Id: I93e4fbc2e8e210cb3fc53149708758bb33f2f9c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/368355 Trust: Jason A. Donenfeld <[email protected]> Run-TryBot: Jason A. Donenfeld <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent b7651e5 commit f0ee7c6

7 files changed

+138
-29
lines changed

src/runtime/sys_darwin.go

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,28 +105,38 @@ func syscallNoErr()
105105
//go:nosplit
106106
//go:cgo_unsafe_args
107107
func pthread_attr_init(attr *pthreadattr) int32 {
108-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
108+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
109+
KeepAlive(attr)
110+
return ret
109111
}
110112
func pthread_attr_init_trampoline()
111113

112114
//go:nosplit
113115
//go:cgo_unsafe_args
114116
func pthread_attr_getstacksize(attr *pthreadattr, size *uintptr) int32 {
115-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
117+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
118+
KeepAlive(attr)
119+
KeepAlive(size)
120+
return ret
116121
}
117122
func pthread_attr_getstacksize_trampoline()
118123

119124
//go:nosplit
120125
//go:cgo_unsafe_args
121126
func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 {
122-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
127+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
128+
KeepAlive(attr)
129+
return ret
123130
}
124131
func pthread_attr_setdetachstate_trampoline()
125132

126133
//go:nosplit
127134
//go:cgo_unsafe_args
128135
func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 {
129-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_create_trampoline)), unsafe.Pointer(&attr))
136+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_create_trampoline)), unsafe.Pointer(&attr))
137+
KeepAlive(attr)
138+
KeepAlive(arg) // Just for consistency. Arg of course needs to be kept alive for the start function.
139+
return ret
130140
}
131141
func pthread_create_trampoline()
132142

@@ -175,27 +185,32 @@ func mmap_trampoline()
175185
//go:cgo_unsafe_args
176186
func munmap(addr unsafe.Pointer, n uintptr) {
177187
libcCall(unsafe.Pointer(abi.FuncPCABI0(munmap_trampoline)), unsafe.Pointer(&addr))
188+
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
178189
}
179190
func munmap_trampoline()
180191

181192
//go:nosplit
182193
//go:cgo_unsafe_args
183194
func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
184195
libcCall(unsafe.Pointer(abi.FuncPCABI0(madvise_trampoline)), unsafe.Pointer(&addr))
196+
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
185197
}
186198
func madvise_trampoline()
187199

188200
//go:nosplit
189201
//go:cgo_unsafe_args
190202
func mlock(addr unsafe.Pointer, n uintptr) {
191203
libcCall(unsafe.Pointer(abi.FuncPCABI0(mlock_trampoline)), unsafe.Pointer(&addr))
204+
KeepAlive(addr) // Just for consistency. Hopefully addr is not a Go address.
192205
}
193206
func mlock_trampoline()
194207

195208
//go:nosplit
196209
//go:cgo_unsafe_args
197210
func read(fd int32, p unsafe.Pointer, n int32) int32 {
198-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(read_trampoline)), unsafe.Pointer(&fd))
211+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(read_trampoline)), unsafe.Pointer(&fd))
212+
KeepAlive(p)
213+
return ret
199214
}
200215
func read_trampoline()
201216

@@ -239,14 +254,18 @@ func usleep_no_g(usec uint32) {
239254
//go:nosplit
240255
//go:cgo_unsafe_args
241256
func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
242-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(write_trampoline)), unsafe.Pointer(&fd))
257+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(write_trampoline)), unsafe.Pointer(&fd))
258+
KeepAlive(p)
259+
return ret
243260
}
244261
func write_trampoline()
245262

246263
//go:nosplit
247264
//go:cgo_unsafe_args
248265
func open(name *byte, mode, perm int32) (ret int32) {
249-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(open_trampoline)), unsafe.Pointer(&name))
266+
ret = libcCall(unsafe.Pointer(abi.FuncPCABI0(open_trampoline)), unsafe.Pointer(&name))
267+
KeepAlive(name)
268+
return
250269
}
251270
func open_trampoline()
252271

@@ -285,13 +304,17 @@ func walltime_trampoline()
285304
//go:cgo_unsafe_args
286305
func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
287306
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaction_trampoline)), unsafe.Pointer(&sig))
307+
KeepAlive(new)
308+
KeepAlive(old)
288309
}
289310
func sigaction_trampoline()
290311

291312
//go:nosplit
292313
//go:cgo_unsafe_args
293314
func sigprocmask(how uint32, new *sigset, old *sigset) {
294315
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigprocmask_trampoline)), unsafe.Pointer(&how))
316+
KeepAlive(new)
317+
KeepAlive(old)
295318
}
296319
func sigprocmask_trampoline()
297320

@@ -306,6 +329,8 @@ func sigaltstack(new *stackt, old *stackt) {
306329
new.ss_size = 32768
307330
}
308331
libcCall(unsafe.Pointer(abi.FuncPCABI0(sigaltstack_trampoline)), unsafe.Pointer(&new))
332+
KeepAlive(new)
333+
KeepAlive(old)
309334
}
310335
func sigaltstack_trampoline()
311336

@@ -320,20 +345,32 @@ func raiseproc_trampoline()
320345
//go:cgo_unsafe_args
321346
func setitimer(mode int32, new, old *itimerval) {
322347
libcCall(unsafe.Pointer(abi.FuncPCABI0(setitimer_trampoline)), unsafe.Pointer(&mode))
348+
KeepAlive(new)
349+
KeepAlive(old)
323350
}
324351
func setitimer_trampoline()
325352

326353
//go:nosplit
327354
//go:cgo_unsafe_args
328355
func sysctl(mib *uint32, miblen uint32, oldp *byte, oldlenp *uintptr, newp *byte, newlen uintptr) int32 {
329-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctl_trampoline)), unsafe.Pointer(&mib))
356+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctl_trampoline)), unsafe.Pointer(&mib))
357+
KeepAlive(mib)
358+
KeepAlive(oldp)
359+
KeepAlive(oldlenp)
360+
KeepAlive(newp)
361+
return ret
330362
}
331363
func sysctl_trampoline()
332364

333365
//go:nosplit
334366
//go:cgo_unsafe_args
335367
func sysctlbyname(name *byte, oldp *byte, oldlenp *uintptr, newp *byte, newlen uintptr) int32 {
336-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctlbyname_trampoline)), unsafe.Pointer(&name))
368+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(sysctlbyname_trampoline)), unsafe.Pointer(&name))
369+
KeepAlive(name)
370+
KeepAlive(oldp)
371+
KeepAlive(oldlenp)
372+
KeepAlive(newp)
373+
return ret
337374
}
338375
func sysctlbyname_trampoline()
339376

@@ -355,56 +392,79 @@ func kqueue_trampoline()
355392
//go:nosplit
356393
//go:cgo_unsafe_args
357394
func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 {
358-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(kevent_trampoline)), unsafe.Pointer(&kq))
395+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(kevent_trampoline)), unsafe.Pointer(&kq))
396+
KeepAlive(ch)
397+
KeepAlive(ev)
398+
KeepAlive(ts)
399+
return ret
359400
}
360401
func kevent_trampoline()
361402

362403
//go:nosplit
363404
//go:cgo_unsafe_args
364405
func pthread_mutex_init(m *pthreadmutex, attr *pthreadmutexattr) int32 {
365-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
406+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
407+
KeepAlive(m)
408+
KeepAlive(attr)
409+
return ret
366410
}
367411
func pthread_mutex_init_trampoline()
368412

369413
//go:nosplit
370414
//go:cgo_unsafe_args
371415
func pthread_mutex_lock(m *pthreadmutex) int32 {
372-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
416+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
417+
KeepAlive(m)
418+
return ret
373419
}
374420
func pthread_mutex_lock_trampoline()
375421

376422
//go:nosplit
377423
//go:cgo_unsafe_args
378424
func pthread_mutex_unlock(m *pthreadmutex) int32 {
379-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
425+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
426+
KeepAlive(m)
427+
return ret
380428
}
381429
func pthread_mutex_unlock_trampoline()
382430

383431
//go:nosplit
384432
//go:cgo_unsafe_args
385433
func pthread_cond_init(c *pthreadcond, attr *pthreadcondattr) int32 {
386-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
434+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
435+
KeepAlive(c)
436+
KeepAlive(attr)
437+
return ret
387438
}
388439
func pthread_cond_init_trampoline()
389440

390441
//go:nosplit
391442
//go:cgo_unsafe_args
392443
func pthread_cond_wait(c *pthreadcond, m *pthreadmutex) int32 {
393-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
444+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
445+
KeepAlive(c)
446+
KeepAlive(m)
447+
return ret
394448
}
395449
func pthread_cond_wait_trampoline()
396450

397451
//go:nosplit
398452
//go:cgo_unsafe_args
399453
func pthread_cond_timedwait_relative_np(c *pthreadcond, m *pthreadmutex, t *timespec) int32 {
400-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
454+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
455+
KeepAlive(c)
456+
KeepAlive(m)
457+
KeepAlive(t)
458+
return ret
401459
}
402460
func pthread_cond_timedwait_relative_np_trampoline()
403461

404462
//go:nosplit
405463
//go:cgo_unsafe_args
406464
func pthread_cond_signal(c *pthreadcond) int32 {
407-
return libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
465+
ret := libcCall(unsafe.Pointer(abi.FuncPCABI0(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
466+
KeepAlive(c)
467+
return ret
408468
}
409469
func pthread_cond_signal_trampoline()
410470

src/runtime/sys_darwin_arm64.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
//go:nosplit
1515
//go:cgo_unsafe_args
1616
func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 {
17-
return asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
17+
ret := asmcgocall(unsafe.Pointer(funcPC(pthread_key_create_trampoline)), unsafe.Pointer(&k))
18+
KeepAlive(k)
19+
return ret
1820
}
1921
func pthread_key_create_trampoline()
2022

src/runtime/sys_openbsd.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,47 @@ import "unsafe"
1515
//go:nosplit
1616
//go:cgo_unsafe_args
1717
func pthread_attr_init(attr *pthreadattr) int32 {
18-
return libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
18+
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
19+
KeepAlive(attr)
20+
return ret
1921
}
2022
func pthread_attr_init_trampoline()
2123

2224
//go:nosplit
2325
//go:cgo_unsafe_args
2426
func pthread_attr_destroy(attr *pthreadattr) int32 {
25-
return libcCall(unsafe.Pointer(funcPC(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr))
27+
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_destroy_trampoline)), unsafe.Pointer(&attr))
28+
KeepAlive(attr)
29+
return ret
2630
}
2731
func pthread_attr_destroy_trampoline()
2832

2933
//go:nosplit
3034
//go:cgo_unsafe_args
3135
func pthread_attr_getstacksize(attr *pthreadattr, size *uintptr) int32 {
32-
return libcCall(unsafe.Pointer(funcPC(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
36+
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_getstacksize_trampoline)), unsafe.Pointer(&attr))
37+
KeepAlive(attr)
38+
KeepAlive(size)
39+
return ret
3340
}
3441
func pthread_attr_getstacksize_trampoline()
3542

3643
//go:nosplit
3744
//go:cgo_unsafe_args
3845
func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 {
39-
return libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
46+
ret := libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
47+
KeepAlive(attr)
48+
return ret
4049
}
4150
func pthread_attr_setdetachstate_trampoline()
4251

4352
//go:nosplit
4453
//go:cgo_unsafe_args
4554
func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 {
46-
return libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
55+
ret := libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
56+
KeepAlive(attr)
57+
KeepAlive(arg) // Just for consistency. Arg of course needs to be kept alive for the start function.
58+
return ret
4759
}
4860
func pthread_create_trampoline()
4961

src/runtime/sys_openbsd1.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import "unsafe"
1212
//go:nosplit
1313
//go:cgo_unsafe_args
1414
func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 {
15-
return libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
15+
ret := libcCall(unsafe.Pointer(funcPC(thrsleep_trampoline)), unsafe.Pointer(&ident))
16+
KeepAlive(tsp)
17+
KeepAlive(abort)
18+
return ret
1619
}
1720
func thrsleep_trampoline()
1821

0 commit comments

Comments
 (0)