From bb96aa6726d1fac7e2500ef37d1193eed00b03f1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 23 Jun 2017 16:05:44 +0000 Subject: [PATCH] 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 --- gcc/go/gofrontend/MERGE | 2 +- libgo/go/runtime/proc.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 02be610b167..473eeca22da 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 77b624ba612..6b6f9c9c379 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -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() }