Commit 4eb17ecd authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: fix goroutine status corruption

runtime.entersyscall() sets g->status = Gsyscall,
then calls runtime.lock() which causes stack split.
runtime.newstack() resets g->status to Grunning.
This will lead to crash during GC (world is not stopped) or GC will scan stack incorrectly.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/10696043
parent b92b0930
...@@ -138,6 +138,7 @@ runtime·oldstack(void) ...@@ -138,6 +138,7 @@ runtime·oldstack(void)
uintptr *src, *dst, *dstend; uintptr *src, *dst, *dstend;
G *gp; G *gp;
int64 goid; int64 goid;
int32 oldstatus;
gp = m->curg; gp = m->curg;
top = (Stktop*)gp->stackbase; top = (Stktop*)gp->stackbase;
...@@ -149,6 +150,10 @@ runtime·oldstack(void) ...@@ -149,6 +150,10 @@ runtime·oldstack(void)
runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n", runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n",
top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize); top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize);
} }
// gp->status is usually Grunning, but it could be Gsyscall if a stack split
// happens during a function call inside entersyscall.
oldstatus = gp->status;
gp->sched = top->gobuf; gp->sched = top->gobuf;
gp->sched.ret = m->cret; gp->sched.ret = m->cret;
...@@ -174,7 +179,7 @@ runtime·oldstack(void) ...@@ -174,7 +179,7 @@ runtime·oldstack(void)
if(top->free != 0) if(top->free != 0)
runtime·stackfree(old, top->free); runtime·stackfree(old, top->free);
gp->status = Grunning; gp->status = oldstatus;
runtime·gogo(&gp->sched); runtime·gogo(&gp->sched);
} }
...@@ -186,7 +191,7 @@ runtime·oldstack(void) ...@@ -186,7 +191,7 @@ runtime·oldstack(void)
void void
runtime·newstack(void) runtime·newstack(void)
{ {
int32 framesize, argsize; int32 framesize, argsize, oldstatus;
Stktop *top; Stktop *top;
byte *stk; byte *stk;
uintptr sp; uintptr sp;
...@@ -196,9 +201,13 @@ runtime·newstack(void) ...@@ -196,9 +201,13 @@ runtime·newstack(void)
bool reflectcall; bool reflectcall;
uintptr free; uintptr free;
// gp->status is usually Grunning, but it could be Gsyscall if a stack split
// happens during a function call inside entersyscall.
gp = m->curg;
oldstatus = gp->status;
framesize = m->moreframesize; framesize = m->moreframesize;
argsize = m->moreargsize; argsize = m->moreargsize;
gp = m->curg;
gp->status = Gwaiting; gp->status = Gwaiting;
gp->waitreason = "stack split"; gp->waitreason = "stack split";
reflectcall = framesize==1; reflectcall = framesize==1;
...@@ -304,7 +313,7 @@ runtime·newstack(void) ...@@ -304,7 +313,7 @@ runtime·newstack(void)
runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt); runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt);
gp->sched.ctxt = nil; gp->sched.ctxt = nil;
} }
gp->status = Grunning; gp->status = oldstatus;
runtime·gogo(&label); runtime·gogo(&label);
*(int32*)345 = 123; // never return *(int32*)345 = 123; // never return
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment