runtime: detect stack split after fork

This check would allowed to easily prevent issue 7511.
Update #7511

LGTM=rsc
R=rsc, aram
CC=golang-codereviews
https://golang.org/cl/75260043
This commit is contained in:
Dmitriy Vyukov 2014-03-13 17:41:08 +04:00
parent 1569628725
commit e678ab4e37
3 changed files with 17 additions and 0 deletions

View file

@ -1704,14 +1704,28 @@ syscall·runtime_BeforeFork(void)
m->locks++; m->locks++;
if(m->profilehz != 0) if(m->profilehz != 0)
runtime·resetcpuprofiler(0); runtime·resetcpuprofiler(0);
// This function is called before fork in syscall package.
// Code between fork and exec must not allocate memory nor even try to grow stack.
// Here we spoil g->stackguard to reliably detect any attempts to grow stack.
// runtime_AfterFork will undo this in parent process, but not in child.
m->forkstackguard = g->stackguard;
g->stackguard0 = StackPreempt-1;
g->stackguard = StackPreempt-1;
} }
// Called from syscall package after fork in parent. // Called from syscall package after fork in parent.
#pragma textflag NOSPLIT
void void
syscall·runtime_AfterFork(void) syscall·runtime_AfterFork(void)
{ {
int32 hz; int32 hz;
// See the comment in runtime_BeforeFork.
g->stackguard0 = m->forkstackguard;
g->stackguard = m->forkstackguard;
m->forkstackguard = 0;
hz = runtime·sched.profilehz; hz = runtime·sched.profilehz;
if(hz != 0) if(hz != 0)
runtime·resetcpuprofiler(hz); runtime·resetcpuprofiler(hz);

View file

@ -367,6 +367,7 @@ struct M
bool needextram; bool needextram;
bool (*waitunlockf)(G*, void*); bool (*waitunlockf)(G*, void*);
void* waitlock; void* waitlock;
uintptr forkstackguard;
#ifdef GOOS_windows #ifdef GOOS_windows
void* thread; // thread handle void* thread; // thread handle
// these are here because they are too large to be on the stack // these are here because they are too large to be on the stack

View file

@ -583,6 +583,8 @@ runtime·newstack(void)
Gobuf label; Gobuf label;
bool newstackcall; bool newstackcall;
if(m->forkstackguard)
runtime·throw("split stack after fork");
if(m->morebuf.g != m->curg) { if(m->morebuf.g != m->curg) {
runtime·printf("runtime: newstack called from g=%p\n" runtime·printf("runtime: newstack called from g=%p\n"
"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n", "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",