stack overflow debugging and fix.

* in 6l, -K already meant check for stack underflow.
    add -KK to mean double-check stack overflows
    even in nosplit functions.

  * comment out print locks; they deadlock too easily
     but are still useful to put back for special occasions.

  * let runcgo assembly switch to scheduler stack
    without involving scheduler directly.  because runcgo
    gets called from matchmg, it is too hard to keep it
    from being called on other stacks.

R=r
DELTA=94  (65 added, 18 deleted, 11 changed)
OCL=35591
CL=35604
This commit is contained in:
Russ Cox 2009-10-12 10:26:38 -07:00
parent fd76b4f385
commit add89dd1ba
7 changed files with 77 additions and 30 deletions

View File

@ -638,6 +638,9 @@ dostkoff(void)
q = P; q = P;
q1 = P; q1 = P;
if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
diag("nosplit func likely to overflow stack");
if(!(p->from.scale & NOSPLIT)) { if(!(p->from.scale & NOSPLIT)) {
if(debug['K']) { if(debug['K']) {
// 6l -K means check not only for stack // 6l -K means check not only for stack
@ -792,8 +795,44 @@ dostkoff(void)
if(q != P) if(q != P)
q->pcond = p; q->pcond = p;
} }
deltasp = autoffset; deltasp = autoffset;
if(debug['K'] > 1 && autoffset) {
// 6l -KK means double-check for stack overflow
// even after calling morestack and even if the
// function is marked as nosplit.
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_INDIR+D_R15;
p->from.offset = 0;
p->to.type = D_BX;
p = appendp(p);
p->as = ASUBQ;
p->from.type = D_CONST;
p->from.offset = StackSmall+32;
p->to.type = D_BX;
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_SP;
p->to.type = D_BX;
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
q1 = p;
p = appendp(p);
p->as = AINT;
p->from.type = D_CONST;
p->from.offset = 3;
p = appendp(p);
p->as = ANOP;
q1->pcond = p;
q1 = P;
}
} }
pcsize = p->mode/8; pcsize = p->mode/8;
a = p->from.type; a = p->from.type;
@ -844,13 +883,12 @@ dostkoff(void)
goto become; goto become;
if(autoffset) { if(autoffset) {
q = p; p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = -autoffset;
p = appendp(p); p = appendp(p);
p->as = ARET; p->as = ARET;
q->as = AADJSP;
q->from.type = D_CONST;
q->from.offset = -autoffset;
} }
continue; continue;

View File

@ -300,12 +300,22 @@ TEXT abort(SB),7,$0
INT $0x3 INT $0x3
// runcgo(void(*fn)(void*), void *arg) // runcgo(void(*fn)(void*), void *arg)
// Just call fn(arg), but first align the stack // Call fn(arg) on the scheduler stack,
// appropriately for the gcc ABI. // aligned appropriately for the gcc ABI.
TEXT runcgo(SB),7,$16 TEXT runcgo(SB),7,$16
MOVL fn+0(FP), AX MOVL fn+0(FP), AX
MOVL arg+4(FP), BX MOVL arg+4(FP), BX
MOVL SP, CX MOVL SP, CX
// Figure out if we need to switch to m->g0 stack.
MOVL m, DX
MOVL m_g0(DX), SI
CMPL g, SI
JEQ 2(PC)
MOVL (m_sched+gobuf_sp)(DX), SP
// Now on a scheduling stack (a pthread-created stack).
SUBL $16, SP
ANDL $~15, SP // alignment for gcc ABI ANDL $~15, SP // alignment for gcc ABI
MOVL CX, 4(SP) MOVL CX, 4(SP)
MOVL BX, 0(SP) MOVL BX, 0(SP)

View File

@ -272,20 +272,32 @@ TEXT jmpdefer(SB), 7, $0
JMP AX // but first run the deferred function JMP AX // but first run the deferred function
// runcgo(void(*fn)(void*), void *arg) // runcgo(void(*fn)(void*), void *arg)
// Call fn(arg), but align the stack // Call fn(arg) on the scheduler stack,
// appropriately for the gcc ABI // aligned appropriately for the gcc ABI.
// and also save g and m across the call, // Save g and m across the call,
// since the foreign code might reuse them. // since the foreign code might reuse them.
TEXT runcgo(SB),7,$32 TEXT runcgo(SB),7,$32
// Save old registers.
MOVQ fn+0(FP),AX MOVQ fn+0(FP),AX
MOVQ arg+8(FP),DI // DI = first argument in AMD64 ABI MOVQ arg+8(FP),DI // DI = first argument in AMD64 ABI
MOVQ SP, CX MOVQ SP, CX
// Figure out if we need to switch to m->g0 stack.
MOVQ m_g0(m), R8
CMPQ R8, g
JEQ 2(PC)
MOVQ (m_sched+gobuf_sp)(m), SP
// Now on a scheduling stack (a pthread-created stack).
SUBQ $32, SP
ANDQ $~15, SP // alignment for gcc ABI ANDQ $~15, SP // alignment for gcc ABI
MOVQ g, 24(SP) // save old g, m, SP MOVQ g, 24(SP) // save old g, m, SP
MOVQ m, 16(SP) MOVQ m, 16(SP)
MOVQ CX, 8(SP) MOVQ CX, 8(SP)
CALL AX CALL AX
MOVQ 16(SP), m // restore
// Restore registers, stack pointer.
MOVQ 16(SP), m
MOVQ 24(SP), g MOVQ 24(SP), g
MOVQ 8(SP), SP MOVQ 8(SP), SP
RET RET

View File

@ -25,10 +25,7 @@ cgocall(void (*fn)(void*), void *arg)
* foreign code. * foreign code.
*/ */
sys·entersyscall(); sys·entersyscall();
g->cgofn = fn; runcgo(fn, arg);
g->cgoarg = arg;
g->status = Gcgocall;
gosched();
sys·exitsyscall(); sys·exitsyscall();
return; return;
} }

View File

@ -4,7 +4,7 @@
#include "runtime.h" #include "runtime.h"
static Lock debuglock; //static Lock debuglock;
void void
dump(byte *p, int32 n) dump(byte *p, int32 n)
@ -37,7 +37,7 @@ printf(int8 *s, ...)
int8 *p, *lp; int8 *p, *lp;
byte *arg, *narg; byte *arg, *narg;
lock(&debuglock); // lock(&debuglock);
lp = p = s; lp = p = s;
arg = (byte*)(&s+1); arg = (byte*)(&s+1);
@ -100,7 +100,7 @@ printf(int8 *s, ...)
if(p > lp) if(p > lp)
write(1, lp, p-lp); write(1, lp, p-lp);
unlock(&debuglock); // unlock(&debuglock);
} }

View File

@ -95,7 +95,7 @@ schedinit(void)
{ {
int32 n; int32 n;
byte *p; byte *p;
allm = m; allm = m;
mallocinit(); mallocinit();
@ -452,15 +452,6 @@ scheduler(void)
lock(&sched); lock(&sched);
if(gosave(&m->sched) != 0){ if(gosave(&m->sched) != 0){
gp = m->curg; gp = m->curg;
if(gp->status == Gcgocall){
// Runtime call into external code (FFI).
// When running with FFI, the scheduler stack is a
// native pthread stack, so it suffices to switch to the
// scheduler stack and make the call.
runcgo(gp->cgofn, gp->cgoarg);
gp->status = Grunning;
gogo(&gp->sched, 1);
}
// Jumped here via gosave/gogo, so didn't // Jumped here via gosave/gogo, so didn't
// execute lock(&sched) above. // execute lock(&sched) above.

View File

@ -94,7 +94,6 @@ enum
Gwaiting, Gwaiting,
Gmoribund, Gmoribund,
Gdead, Gdead,
Gcgocall,
}; };
enum enum
{ {