runtime: don't use pointers in g_ucontext_t or stackcontext
The g_ucontext_t type holds registers saved for a goroutine. We have
to scan it for pointers, but since registers don't necessarily hold
pointers we have to scan it conservatively. That means that it should
not have a pointer type, since the GC will always scan pointers.
Instead it needs special treatment to be scanned conservatively.
The current GC doesn't care when a pointer type holds a non-pointer,
but the Go 1.8 GC does.
For the current GC this means we have to explicitly scan the
g_ucontext_t values in a G.
While we're at it change stackcontext to be uintptr too. The entries
in stackcontext never hold pointers that the Go GC cares about.
Change-Id: I10c9dab28ce8b992be1a61c9be681af1c35c256e
Reviewed-on: https://go-review.googlesource.com/41270
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
index 69769f9..9c5def2 100644
--- a/libgo/go/runtime/runtime2.go
+++ b/libgo/go/runtime/runtime2.go
@@ -418,8 +418,8 @@
traceback *tracebackg // stack traceback buffer
- context g_ucontext_t // saved context for setcontext
- stackcontext [10]unsafe.Pointer // split-stack context
+ context g_ucontext_t // saved context for setcontext
+ stackcontext [10]uintptr // split-stack context
}
type m struct {
@@ -787,7 +787,7 @@
// aligned to a 16-byte boundary. We implement this by increasing the
// required size and picking an appropriate offset when we use the
// array.
-type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
+type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(uintptr(0))]uintptr
// sigset is the Go version of the C type sigset_t.
// _sigset_t is defined by the Makefile from <signal.h>.
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
index 711f71e..ad29662 100644
--- a/libgo/runtime/go-signal.c
+++ b/libgo/runtime/go-signal.c
@@ -91,7 +91,7 @@
__splitstack_getcontext(&stack_context[0]);
- stack = __splitstack_find_context(&gp->m->gsignal->stackcontext[0],
+ stack = __splitstack_find_context((void*)(&gp->m->gsignal->stackcontext[0]),
&stack_size, &next_segment,
&next_sp, &initial_sp);
@@ -126,7 +126,7 @@
// Set the split stack context so that the stack guards are
// checked correctly.
- __splitstack_setcontext(&gp->m->gsignal->stackcontext[0]);
+ __splitstack_setcontext((void*)(&gp->m->gsignal->stackcontext[0]));
sigtrampgo(sig, info, context);
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 8e7d7ef..9a15a1d 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -1452,6 +1452,12 @@
break;
}
+ // Explicitly scan the saved contexts.
+ // We have to pass defaultProg to prevent scanblock from looking
+ // up the pointer to get the type.
+ enqueue1(wbufp, (Obj){(byte*)(&gp->gcregs[0]), sizeof(gp->gcregs), (uintptr)(&defaultProg[0])});
+ enqueue1(wbufp, (Obj){(byte*)(&gp->context[0]), sizeof(gp->context), (uintptr)(&defaultProg[0])});
+
#ifdef USING_SPLIT_STACK
M *mp;
void* sp;
@@ -1483,7 +1489,7 @@
next_sp = gp->gcnextsp;
initial_sp = gp->gcinitialsp;
} else {
- sp = __splitstack_find_context(&gp->stackcontext[0],
+ sp = __splitstack_find_context((void*)(&gp->stackcontext[0]),
&spsize, &next_segment,
&next_sp, &initial_sp);
}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 5febe0c..fb40797 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -181,7 +181,7 @@
// So we make the field larger in runtime2.go and pick an appropriate
// offset within the field here.
static ucontext_t*
-ucontext_arg(void** go_ucontext)
+ucontext_arg(uintptr* go_ucontext)
{
uintptr_t p = (uintptr_t)go_ucontext;
size_t align = __alignof__(ucontext_t);
@@ -279,7 +279,7 @@
runtime_gogo(G* newg)
{
#ifdef USING_SPLIT_STACK
- __splitstack_setcontext(&newg->stackcontext[0]);
+ __splitstack_setcontext((void*)(&newg->stackcontext[0]));
#endif
g = newg;
newg->fromgogo = true;
@@ -314,7 +314,7 @@
if(gp != nil) {
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&g->stackcontext[0]);
+ __splitstack_getcontext((void*)(&g->stackcontext[0]));
#else
// We have to point to an address on the stack that is
// below the saved registers.
@@ -338,7 +338,7 @@
}
if (gp == nil || !gp->fromgogo) {
#ifdef USING_SPLIT_STACK
- __splitstack_setcontext(&mp->g0->stackcontext[0]);
+ __splitstack_setcontext((void*)(&mp->g0->stackcontext[0]));
#endif
mp->g0->entry = fv;
mp->g0->param = gp;
@@ -431,7 +431,7 @@
void getTraceback(G* me, G* gp)
{
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&me->stackcontext[0]);
+ __splitstack_getcontext((void*)(&me->stackcontext[0]));
#endif
getcontext(ucontext_arg(&me->context[0]));
@@ -483,7 +483,7 @@
// Once we call schedule we're never coming back,
// so other calls can reuse this stack space.
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&gp->stackcontext[0]);
+ __splitstack_getcontext((void*)(&gp->stackcontext[0]));
#else
gp->gcinitialsp = &arg;
// Setting gcstacksize to 0 is a marker meaning that gcinitialsp
@@ -553,7 +553,7 @@
gp->entry = nil;
gp->param = nil;
#ifdef USING_SPLIT_STACK
- __splitstack_getcontext(&gp->stackcontext[0]);
+ __splitstack_getcontext((void*)(&gp->stackcontext[0]));
val = 0;
__splitstack_block_signals(&val, nil);
#else
@@ -715,10 +715,10 @@
#if USING_SPLIT_STACK
*ret_stack = __splitstack_makecontext(stacksize,
- &newg->stackcontext[0],
+ (void*)(&newg->stackcontext[0]),
&ss_stacksize);
*ret_stacksize = (uintptr)ss_stacksize;
- __splitstack_block_signals_context(&newg->stackcontext[0],
+ __splitstack_block_signals_context((void*)(&newg->stackcontext[0]),
&dont_block_signals, nil);
#else
// In 64-bit mode, the maximum Go allocation space is
@@ -756,9 +756,9 @@
int dont_block_signals = 0;
size_t ss_spsize;
- *sp = __splitstack_resetcontext(&newg->stackcontext[0], &ss_spsize);
+ *sp = __splitstack_resetcontext((void*)(&newg->stackcontext[0]), &ss_spsize);
*spsize = ss_spsize;
- __splitstack_block_signals_context(&newg->stackcontext[0],
+ __splitstack_block_signals_context((void*)(&newg->stackcontext[0]),
&dont_block_signals, nil);
#else
*sp = newg->gcinitialsp;