Skip to content

Commit 21b4f23

Browse files
runtime: for c-archive/c-shared, install signal handlers synchronously
The previous behaviour of installing the signal handlers in a separate thread meant that Go initialization raced with non-Go initialization if the non-Go initialization also wanted to install signal handlers. Make installing signal handlers synchronous so that the process-wide behavior is predictable. Update #9896. Change-Id: Ice24299877ec46f8518b072a381932d273096a32 Reviewed-on: https://go-review.googlesource.com/18150 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: David Crawshaw <[email protected]>
1 parent 0b3807a commit 21b4f23

23 files changed

+200
-12
lines changed

misc/cgo/testcarchive/main.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,44 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5+
#include <signal.h>
56
#include <stdint.h>
67
#include <stdio.h>
8+
#include <string.h>
79

810
#include "p.h"
911
#include "libgo.h"
1012

13+
static void (*oldHandler)(int, siginfo_t*, void*);
14+
15+
static void handler(int signo, siginfo_t* info, void* ctxt) {
16+
if (oldHandler) {
17+
oldHandler(signo, info, ctxt);
18+
}
19+
}
20+
1121
int main(void) {
22+
struct sigaction sa;
23+
struct sigaction osa;
1224
int32_t res;
1325

26+
// Install our own signal handler.
27+
memset(&sa, 0, sizeof sa);
28+
sa.sa_sigaction = handler;
29+
sigemptyset(&sa.sa_mask);
30+
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
31+
memset(&osa, 0, sizeof osa);
32+
sigemptyset(&osa.sa_mask);
33+
if (sigaction(SIGSEGV, &sa, &osa) < 0) {
34+
perror("sigaction");
35+
return 2;
36+
}
37+
if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) {
38+
fprintf(stderr, "Go runtime did not install signal handler\n");
39+
return 2;
40+
}
41+
oldHandler = osa.sa_sigaction;
42+
1443
if (!DidInitRun()) {
1544
fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
1645
return 2;
@@ -21,6 +50,16 @@ int main(void) {
2150
return 2;
2251
}
2352

53+
// Make sure our signal handler is still the one in use.
54+
if (sigaction(SIGSEGV, NULL, &sa) < 0) {
55+
perror("sigaction check");
56+
return 2;
57+
}
58+
if (sa.sa_sigaction != handler) {
59+
fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler);
60+
return 2;
61+
}
62+
2463
res = FromPkg();
2564
if (res != 1024) {
2665
fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res);

src/os/signal/doc.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ When Go code is built with options like -buildmode=c-shared, it will
172172
be run as part of an existing non-Go program. The non-Go code may
173173
have already installed signal handlers when the Go code starts (that
174174
may also happen in unusual cases when using cgo or SWIG; in that case,
175-
the discussion here applies).
175+
the discussion here applies). For -buildmode=c-archive the Go runtime
176+
will initialize signals at global constructor time. For
177+
-buildmode=c-shared the Go runtime will initialize signals when the
178+
shared library is loaded.
176179
177180
If the Go runtime sees an existing signal handler for the SIGCANCEL or
178181
SIGSETXID signals (which are used only on GNU/Linux), it will turn on

src/runtime/os1_darwin.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) {
125125
var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
126126
var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
127127

128+
// Called to do synchronous initialization of Go code built with
129+
// -buildmode=c-archive or -buildmode=c-shared.
130+
// None of the Go runtime is initialized.
131+
//go:nosplit
132+
//go:nowritebarrierrec
133+
func libpreinit() {
134+
initsig(true)
135+
}
136+
128137
// Called to initialize a new m (including the bootstrap m).
129138
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
130139
func mpreinit(mp *m) {
@@ -459,6 +468,8 @@ func memlimit() uintptr {
459468
return 0
460469
}
461470

471+
//go:nosplit
472+
//go:nowritebarrierrec
462473
func setsig(i int32, fn uintptr, restart bool) {
463474
var sa sigactiont
464475
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
@@ -471,6 +482,8 @@ func setsig(i int32, fn uintptr, restart bool) {
471482
sigaction(uint32(i), &sa, nil)
472483
}
473484

485+
//go:nosplit
486+
//go:nowritebarrierrec
474487
func setsigstack(i int32) {
475488
var osa usigactiont
476489
sigaction(uint32(i), nil, &osa)
@@ -486,6 +499,8 @@ func setsigstack(i int32) {
486499
sigaction(uint32(i), &sa, nil)
487500
}
488501

502+
//go:nosplit
503+
//go:nowritebarrierrec
489504
func getsig(i int32) uintptr {
490505
var sa usigactiont
491506
sigaction(uint32(i), nil, &sa)
@@ -505,6 +520,8 @@ func signalstack(s *stack) {
505520
sigaltstack(&st, nil)
506521
}
507522

523+
//go:nosplit
524+
//go:nowritebarrierrec
508525
func updatesigmask(m sigmask) {
509526
s := sigset(m[0])
510527
sigprocmask(_SIG_SETMASK, &s, nil)

src/runtime/os1_dragonfly.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ type sigactiont struct {
213213
sa_mask sigset
214214
}
215215

216+
//go:nosplit
217+
//go:nowritebarrierrec
216218
func setsig(i int32, fn uintptr, restart bool) {
217219
var sa sigactiont
218220
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
@@ -227,10 +229,14 @@ func setsig(i int32, fn uintptr, restart bool) {
227229
sigaction(i, &sa, nil)
228230
}
229231

232+
//go:nosplit
233+
//go:nowritebarrierrec
230234
func setsigstack(i int32) {
231235
throw("setsigstack")
232236
}
233237

238+
//go:nosplit
239+
//go:nowritebarrierrec
234240
func getsig(i int32) uintptr {
235241
var sa sigactiont
236242
sigaction(i, nil, &sa)
@@ -253,6 +259,8 @@ func signalstack(s *stack) {
253259
sigaltstack(&st, nil)
254260
}
255261

262+
//go:nosplit
263+
//go:nowritebarrierrec
256264
func updatesigmask(m sigmask) {
257265
var mask sigset
258266
copy(mask.__bits[:], m[:])

src/runtime/os1_freebsd.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ type sigactiont struct {
220220
sa_mask sigset
221221
}
222222

223+
//go:nosplit
224+
//go:nowritebarrierrec
223225
func setsig(i int32, fn uintptr, restart bool) {
224226
var sa sigactiont
225227
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
@@ -234,10 +236,14 @@ func setsig(i int32, fn uintptr, restart bool) {
234236
sigaction(i, &sa, nil)
235237
}
236238

239+
//go:nosplit
240+
//go:nowritebarrierrec
237241
func setsigstack(i int32) {
238242
throw("setsigstack")
239243
}
240244

245+
//go:nosplit
246+
//go:nowritebarrierrec
241247
func getsig(i int32) uintptr {
242248
var sa sigactiont
243249
sigaction(i, nil, &sa)
@@ -260,6 +266,8 @@ func signalstack(s *stack) {
260266
sigaltstack(&st, nil)
261267
}
262268

269+
//go:nosplit
270+
//go:nowritebarrierrec
263271
func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
264272
var mask sigset
265273
copy(mask.__bits[:], m[:])

src/runtime/os1_linux.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,15 @@ func goenvs() {
190190
goenvs_unix()
191191
}
192192

193+
// Called to do synchronous initialization of Go code built with
194+
// -buildmode=c-archive or -buildmode=c-shared.
195+
// None of the Go runtime is initialized.
196+
//go:nosplit
197+
//go:nowritebarrierrec
198+
func libpreinit() {
199+
initsig(true)
200+
}
201+
193202
// Called to initialize a new m (including the bootstrap m).
194203
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
195204
func mpreinit(mp *m) {
@@ -298,6 +307,8 @@ func memlimit() uintptr {
298307
func sigreturn()
299308
func sigtramp()
300309

310+
//go:nosplit
311+
//go:nowritebarrierrec
301312
func setsig(i int32, fn uintptr, restart bool) {
302313
var sa sigactiont
303314
memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
@@ -316,12 +327,11 @@ func setsig(i int32, fn uintptr, restart bool) {
316327
fn = funcPC(sigtramp)
317328
}
318329
sa.sa_handler = fn
319-
// Qemu rejects rt_sigaction of SIGRTMAX (64).
320-
if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 && i != 64 {
321-
throw("rt_sigaction failure")
322-
}
330+
rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask))
323331
}
324332

333+
//go:nosplit
334+
//go:nowritebarrierrec
325335
func setsigstack(i int32) {
326336
var sa sigactiont
327337
if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
@@ -336,6 +346,8 @@ func setsigstack(i int32) {
336346
}
337347
}
338348

349+
//go:nosplit
350+
//go:nowritebarrierrec
339351
func getsig(i int32) uintptr {
340352
var sa sigactiont
341353

@@ -362,6 +374,8 @@ func signalstack(s *stack) {
362374
sigaltstack(&st, nil)
363375
}
364376

377+
//go:nosplit
378+
//go:nowritebarrierrec
365379
func updatesigmask(m sigmask) {
366380
var mask sigset
367381
sigcopyset(&mask, m)

src/runtime/os1_nacl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func goenvs() {
6767
goenvs_unix()
6868
}
6969

70-
func initsig() {
70+
func initsig(preinit bool) {
7171
}
7272

7373
//go:nosplit

src/runtime/os1_netbsd.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ type sigactiont struct {
206206
sa_flags int32
207207
}
208208

209+
//go:nosplit
210+
//go:nowritebarrierrec
209211
func setsig(i int32, fn uintptr, restart bool) {
210212
var sa sigactiont
211213
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
@@ -220,10 +222,14 @@ func setsig(i int32, fn uintptr, restart bool) {
220222
sigaction(i, &sa, nil)
221223
}
222224

225+
//go:nosplit
226+
//go:nowritebarrierrec
223227
func setsigstack(i int32) {
224228
throw("setsigstack")
225229
}
226230

231+
//go:nosplit
232+
//go:nowritebarrierrec
227233
func getsig(i int32) uintptr {
228234
var sa sigactiont
229235
sigaction(i, nil, &sa)
@@ -246,6 +252,8 @@ func signalstack(s *stack) {
246252
sigaltstack(&st, nil)
247253
}
248254

255+
//go:nosplit
256+
//go:nowritebarrierrec
249257
func updatesigmask(m sigmask) {
250258
var mask sigset
251259
copy(mask.__bits[:], m[:])

src/runtime/os1_openbsd.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ type sigactiont struct {
220220
sa_flags int32
221221
}
222222

223+
//go:nosplit
224+
//go:nowritebarrierrec
223225
func setsig(i int32, fn uintptr, restart bool) {
224226
var sa sigactiont
225227
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
@@ -234,10 +236,14 @@ func setsig(i int32, fn uintptr, restart bool) {
234236
sigaction(i, &sa, nil)
235237
}
236238

239+
//go:nosplit
240+
//go:nowritebarrierrec
237241
func setsigstack(i int32) {
238242
throw("setsigstack")
239243
}
240244

245+
//go:nosplit
246+
//go:nowritebarrierrec
241247
func getsig(i int32) uintptr {
242248
var sa sigactiont
243249
sigaction(i, nil, &sa)
@@ -260,6 +266,8 @@ func signalstack(s *stack) {
260266
sigaltstack(&st, nil)
261267
}
262268

269+
//go:nosplit
270+
//go:nowritebarrierrec
263271
func updatesigmask(m sigmask) {
264272
sigprocmask(_SIG_SETMASK, sigset(m[0]))
265273
}

src/runtime/os1_plan9.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func getRandomData(r []byte) {
107107
func goenvs() {
108108
}
109109

110-
func initsig() {
110+
func initsig(preinit bool) {
111111
}
112112

113113
//go:nosplit

src/runtime/os3_solaris.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ func memlimit() uintptr {
279279

280280
func sigtramp()
281281

282+
//go:nosplit
283+
//go:nowritebarrierrec
282284
func setsig(i int32, fn uintptr, restart bool) {
283285
var sa sigactiont
284286

@@ -295,6 +297,8 @@ func setsig(i int32, fn uintptr, restart bool) {
295297
sigaction(i, &sa, nil)
296298
}
297299

300+
//go:nosplit
301+
//go:nowritebarrierrec
298302
func setsigstack(i int32) {
299303
var sa sigactiont
300304
sigaction(i, nil, &sa)
@@ -306,6 +310,8 @@ func setsigstack(i int32) {
306310
sigaction(i, &sa, nil)
307311
}
308312

313+
//go:nosplit
314+
//go:nowritebarrierrec
309315
func getsig(i int32) uintptr {
310316
var sa sigactiont
311317
sigaction(i, nil, &sa)
@@ -328,6 +334,8 @@ func signalstack(s *stack) {
328334
sigaltstack(&st, nil)
329335
}
330336

337+
//go:nosplit
338+
//go:nowritebarrierrec
331339
func updatesigmask(m sigmask) {
332340
var mask sigset
333341
copy(mask.__sigbits[:], m[:])
@@ -478,6 +486,8 @@ func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.P
478486
return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
479487
}
480488

489+
//go:nosplit
490+
//go:nowritebarrierrec
481491
func raise(sig int32) /* int32 */ {
482492
sysvicall1(&libc_raise, uintptr(sig))
483493
}
@@ -516,6 +526,8 @@ func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
516526
sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
517527
}
518528

529+
//go:nosplit
530+
//go:nowritebarrierrec
519531
func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
520532
sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
521533
}
@@ -527,6 +539,7 @@ func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
527539
}
528540

529541
//go:nosplit
542+
//go:nowritebarrierrec
530543
func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
531544
sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
532545
}

0 commit comments

Comments
 (0)