From c81a0ed3c50606d1ada0fd9b571611b3687c90e1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 14:05:23 -0400 Subject: liblink, runtime: diagnose and fix C code running on Go stack This CL contains compiler+runtime changes that detect C code running on Go (not g0, not gsignal) stacks, and it contains corrections for what it detected. The detection works by changing the C prologue to use a different stack guard word in the G than Go prologue does. On the g0 and gsignal stacks, that stack guard word is set to the usual stack guard value. But on ordinary Go stacks, that stack guard word is set to ^0, which will make any stack split check fail. The C prologue then calls morestackc instead of morestack, and morestackc aborts the program with a message about running C code on a Go stack. This check catches all C code running on the Go stack except NOSPLIT code. The NOSPLIT code is allowed, so the check is complete. Since it is a dynamic check, the code must execute to be caught. But unlike the static checks we've been using in cmd/ld, the dynamic check works with function pointers and other indirect calls. For example it caught sigpanic being pushed onto Go stacks in the signal handlers. Fixes #8667. LGTM=khr, iant R=golang-codereviews, khr, iant CC=golang-codereviews, r https://golang.org/cl/133700043 --- src/runtime/stack.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'src/runtime/stack.c') diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 18b3f40648..bb8c7ac11b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -428,13 +428,6 @@ checkframecopy(Stkframe *frame, void *arg) runtime·printf(" \n"); return false; // stop traceback } - if(f->entry == (uintptr)runtime·main) { - // A special routine at the TOS of the main routine. - // We will allow it to be copied even though we don't - // have full GC info for it (because it is written in C). - cinfo->frames++; - return false; // stop traceback - } if(f->entry == (uintptr)runtime·switchtoM) { // A special routine at the bottom of stack of a goroutine that does onM call. // We will allow it to be copied even though we don't @@ -657,8 +650,7 @@ adjustframe(Stkframe *frame, void *arg) f = frame->fn; if(StackDebug >= 2) runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); - if(f->entry == (uintptr)runtime·main || - f->entry == (uintptr)runtime·switchtoM) + if(f->entry == (uintptr)runtime·switchtoM) return true; targetpc = frame->continpc; if(targetpc == 0) { @@ -1126,3 +1118,21 @@ runtime·shrinkstack(G *gp) return; copystack(gp, nframes, newsize); } + +static void badc(void); + +#pragma textflag NOSPLIT +void +runtime·morestackc(void) +{ + void (*fn)(void); + + fn = badc; + runtime·onM(&fn); +} + +static void +badc(void) +{ + runtime·throw("attempt to execute C code on Go stack"); +} -- cgit v1.3-5-g9baa