Skip to content

Commit 6640ea9

Browse files
committed
runtime: fix infinite loop in lockextra on linux/arm
This commit fixes issue golang#34391, which is due to an incorrect patch merged in golang#34030. sigtrampgo is modified to record incoming signals in a globally shared atomic bitmask during when the G register is clobbered. When the execution exits from vdso it checks if there is a pending signal it re-raises them to its own process.
1 parent d5cfcc7 commit 6640ea9

File tree

3 files changed

+53
-14
lines changed

3 files changed

+53
-14
lines changed

src/runtime/signal_unix.go

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,37 @@ func sigpipe() {
274274
dieFromSignal(_SIGPIPE)
275275
}
276276

277-
// sigFetchG fetches the value of G safely when running in a signal handler.
278277
// On some architectures, the g value may be clobbered when running in a VDSO.
279278
// See issue #32912.
280279
//
281280
//go:nosplit
282-
func sigFetchG(c *sigctxt) *g {
281+
func sigClobbered(c *sigctxt) bool {
283282
switch GOARCH {
284283
case "arm", "arm64":
285-
if inVDSOPage(c.sigpc()) {
286-
return nil
287-
}
284+
return inVDSOPage(c.sigpc());
285+
}
286+
return false
287+
}
288+
289+
// sigpending stores signals during the Go signal handler when the g value is clobbered.
290+
// See issue #34391.
291+
var sigpending [(_NSIG + 31) / 32]uint32
292+
293+
func sigAddPending(s uint32) {
294+
p := sigpending[s/32]
295+
p |= 1 << (s & 31)
296+
atomic.Store(&sigpending[s/32], p)
297+
}
298+
299+
// sigClearPending is called from outside the signal handler context.
300+
// It is called just after the clobbered G value is restored.
301+
func sigClearPending() {
302+
for s := 0; s < _NSIG; s++ {
303+
p := sigpending[s/32]
304+
p &^= 1 << (s & 31)
305+
atomic.Store(&sigpending[s/32], p)
306+
raise(uint32(s))
288307
}
289-
return getg()
290308
}
291309

292310
// sigtrampgo is called from the signal handler function, sigtramp,
@@ -305,7 +323,16 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
305323
return
306324
}
307325
c := &sigctxt{info, ctx}
308-
g := sigFetchG(c)
326+
if sigClobbered(c) {
327+
if sig == _SIGPROF {
328+
sigprofNonGoPC(c.sigpc())
329+
return
330+
}
331+
// at this point iscgo must be true
332+
sigAddPending(sig)
333+
return
334+
}
335+
g := getg()
309336
if g == nil {
310337
if sig == _SIGPROF {
311338
sigprofNonGoPC(c.sigpc())
@@ -670,13 +697,19 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
670697
if (c.sigcode() == _SI_USER || flags&_SigPanic == 0) && sig != _SIGPIPE {
671698
return false
672699
}
673-
// Determine if the signal occurred inside Go code. We test that:
674-
// (1) we weren't in VDSO page,
675-
// (2) we were in a goroutine (i.e., m.curg != nil), and
676-
// (3) we weren't in CGO.
677-
g := sigFetchG(c)
678-
if g != nil && g.m != nil && g.m.curg != nil && !g.m.incgo {
679-
return false
700+
if sigClobbered(c) {
701+
// There is no handler to be forwarded to.
702+
if !iscgo {
703+
return false
704+
}
705+
} else {
706+
// Determine if the signal occurred inside Go code. We test that:
707+
// (1) we were in a goroutine (i.e., m.curg != nil), and
708+
// (2) we weren't in CGO.
709+
g := getg()
710+
if g != nil && g.m != nil && g.m.curg != nil && !g.m.incgo {
711+
return false
712+
}
680713
}
681714

682715
// Signal not handled by Go, forward it.

src/runtime/sys_linux_arm.s

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ noswitch:
247247
B.EQ fallback
248248

249249
BL (R11)
250+
251+
BL runtime·sigClearPending(SB)
250252
JMP finish
251253

252254
fallback:
@@ -298,6 +300,8 @@ noswitch:
298300
B.EQ fallback
299301

300302
BL (R11)
303+
304+
BL runtime·sigClearPending(SB)
301305
JMP finish
302306

303307
fallback:

src/runtime/sys_linux_arm64.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ noswitch:
208208
MOVD runtime·vdsoClockgettimeSym(SB), R2
209209
CBZ R2, fallback
210210
BL (R2)
211+
BL runtime·sigClearPending(SB)
211212
B finish
212213

213214
fallback:
@@ -251,6 +252,7 @@ noswitch:
251252
MOVD runtime·vdsoClockgettimeSym(SB), R2
252253
CBZ R2, fallback
253254
BL (R2)
255+
BL runtime·sigClearPending(SB)
254256
B finish
255257

256258
fallback:

0 commit comments

Comments
 (0)