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
merge done from the gofrontend repository.

View File

@ -1097,7 +1097,25 @@ func kickoff() {
fv := gp.entry
param := gp.param
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
fv(param)
goexit1()
}