runtime: don't crash if no p in kickoff

The kickoff function for g0 can be invoked without a p, for example
    from mcall(exitsyscall0) in exitsyscall after exitsyscall has cleared
    the p field. The assignment gp.param = nil will invoke a write barrier.
    If gp.param is not already nil, this will require a p. Avoid the problem
    for a specific case that is known to be OK: when the value in gp.param
    is a *g.
    
    Reviewed-on: https://go-review.googlesource.com/46512

From-SVN: r249595
This commit is contained in:
Ian Lance Taylor 2017-06-23 16:05:44 +00:00
parent 5f0b897b2e
commit bb96aa6726
2 changed files with 19 additions and 1 deletions

View File

@ -1,4 +1,4 @@
29c61dc3c5151df5de9362b7882ccf04679df976 f107cc8bced1939b0083231fc1ea24669ca4832c
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.

View File

@ -1097,7 +1097,25 @@ func kickoff() {
fv := gp.entry fv := gp.entry
param := gp.param param := gp.param
gp.entry = nil gp.entry = nil
// When running on the g0 stack we can wind up here without a p,
// for example from mcall(exitsyscall0) in exitsyscall.
// Setting gp.param = nil will call a write barrier, and if
// there is no p that write barrier will crash. When called from
// mcall the gp.param value will be a *g, which we don't need to
// shade since we know it will be kept alive elsewhere. In that
// case clear the field using uintptr so that the write barrier
// does nothing.
if gp.m.p == 0 {
if gp == gp.m.g0 && gp.param == unsafe.Pointer(gp.m.curg) {
*(*uintptr)(unsafe.Pointer(&gp.param)) = 0
} else {
throw("no p in kickoff")
}
}
gp.param = nil gp.param = nil
fv(param) fv(param)
goexit1() goexit1()
} }