Commit c2dd33a4 authored by Russ Cox's avatar Russ Cox

cmd/ld: clear unused ctxt before morestack

For non-closure functions, the context register is uninitialized
on entry and will not be used, but morestack saves it and then the
garbage collector treats it as live. This can be a source of memory
leaks if the context register points at otherwise dead memory.
Avoid this by introducing a parallel set of morestack functions
that clear the context register, and use those for the non-closure functions.

I hope this will help with some of the finalizer flakiness, but it probably won't.

Fixes #7244.

LGTM=dvyukov
R=khr, dvyukov
CC=golang-codereviews
https://golang.org/cl/71030044
parent 542415c9
...@@ -356,7 +356,7 @@ struct Link ...@@ -356,7 +356,7 @@ struct Link
LSym* sym_divu; LSym* sym_divu;
LSym* sym_mod; LSym* sym_mod;
LSym* sym_modu; LSym* sym_modu;
LSym* symmorestack[10]; LSym* symmorestack[20];
LSym* gmsym; LSym* gmsym;
LSym* plan9tos; LSym* plan9tos;
Prog* curp; Prog* curp;
......
...@@ -1264,6 +1264,8 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1264,6 +1264,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break; break;
case OCLOSUREVAR: case OCLOSUREVAR:
if(!curfn->needctxt)
fatal("closurevar without needctxt");
a->type = D_OREG; a->type = D_OREG;
a->reg = 7; a->reg = 7;
a->offset = n->xoffset; a->offset = n->xoffset;
......
...@@ -1186,6 +1186,8 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -1186,6 +1186,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break; break;
case OCLOSUREVAR: case OCLOSUREVAR:
if(!curfn->needctxt)
fatal("closurevar without needctxt");
a->type = D_DX+D_INDIR; a->type = D_DX+D_INDIR;
a->sym = nil; a->sym = nil;
a->offset = n->xoffset; a->offset = n->xoffset;
......
...@@ -2211,6 +2211,8 @@ naddr(Node *n, Addr *a, int canemitcode) ...@@ -2211,6 +2211,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break; break;
case OCLOSUREVAR: case OCLOSUREVAR:
if(!curfn->needctxt)
fatal("closurevar without needctxt");
a->type = D_DX+D_INDIR; a->type = D_DX+D_INDIR;
a->offset = n->xoffset; a->offset = n->xoffset;
a->sym = nil; a->sym = nil;
......
...@@ -161,6 +161,7 @@ makeclosure(Node *func) ...@@ -161,6 +161,7 @@ makeclosure(Node *func)
// and initialize in entry prologue. // and initialize in entry prologue.
body = nil; body = nil;
offset = widthptr; offset = widthptr;
xfunc->needctxt = func->cvars != nil;
for(l=func->cvars; l; l=l->next) { for(l=func->cvars; l; l=l->next) {
v = l->n; v = l->n;
if(v->op == 0) if(v->op == 0)
...@@ -361,6 +362,7 @@ makepartialcall(Node *fn, Type *t0, Node *meth) ...@@ -361,6 +362,7 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
// Declare and initialize variable holding receiver. // Declare and initialize variable holding receiver.
body = nil; body = nil;
xfunc->needctxt = 1;
cv = nod(OCLOSUREVAR, N, N); cv = nod(OCLOSUREVAR, N, N);
cv->xoffset = widthptr; cv->xoffset = widthptr;
cv->type = rcvrtype; cv->type = rcvrtype;
......
...@@ -283,6 +283,7 @@ struct Node ...@@ -283,6 +283,7 @@ struct Node
schar likely; // likeliness of if statement schar likely; // likeliness of if statement
uchar hasbreak; // has break statement uchar hasbreak; // has break statement
uchar needzero; // if it contains pointers, needs to be zeroed on function entry uchar needzero; // if it contains pointers, needs to be zeroed on function entry
uchar needctxt; // function uses context register (has closure variables)
uint esc; // EscXXX uint esc; // EscXXX
int funcdepth; int funcdepth;
......
...@@ -192,6 +192,8 @@ compile(Node *fn) ...@@ -192,6 +192,8 @@ compile(Node *fn)
ptxt->TEXTFLAG |= DUPOK; ptxt->TEXTFLAG |= DUPOK;
if(fn->wrapper) if(fn->wrapper)
ptxt->TEXTFLAG |= WRAPPER; ptxt->TEXTFLAG |= WRAPPER;
if(fn->needctxt)
ptxt->TEXTFLAG |= NEEDCTXT;
// Clumsy but important. // Clumsy but important.
// See test/recover.go for test cases and src/pkg/reflect/value.go // See test/recover.go for test cases and src/pkg/reflect/value.go
......
...@@ -19,3 +19,5 @@ ...@@ -19,3 +19,5 @@
#define NOPTR 16 #define NOPTR 16
// This is a wrapper function and should not count as disabling 'recover'. // This is a wrapper function and should not count as disabling 'recover'.
#define WRAPPER 32 #define WRAPPER 32
// This function uses its incoming context register.
#define NEEDCTXT 64
...@@ -194,7 +194,7 @@ prg(void) ...@@ -194,7 +194,7 @@ prg(void)
return p; return p;
} }
static Prog* stacksplit(Link*, Prog*, int32); static Prog* stacksplit(Link*, Prog*, int32, int);
static void initdiv(Link*); static void initdiv(Link*);
static void softfloat(Link*, LSym*); static void softfloat(Link*, LSym*);
...@@ -237,8 +237,10 @@ addstacksplit(Link *ctxt, LSym *cursym) ...@@ -237,8 +237,10 @@ addstacksplit(Link *ctxt, LSym *cursym)
autosize = 0; autosize = 0;
if(ctxt->symmorestack[0] == nil) if(ctxt->symmorestack[0] == nil) {
ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
}
q = nil; q = nil;
...@@ -409,7 +411,7 @@ addstacksplit(Link *ctxt, LSym *cursym) ...@@ -409,7 +411,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
} }
if(!(p->reg & NOSPLIT)) if(!(p->reg & NOSPLIT))
p = stacksplit(ctxt, p, autosize); // emit split check p = stacksplit(ctxt, p, autosize, !(cursym->text->from.scale&NEEDCTXT)); // emit split check
// MOVW.W R14,$-autosize(SP) // MOVW.W R14,$-autosize(SP)
p = appendp(ctxt, p); p = appendp(ctxt, p);
...@@ -727,7 +729,7 @@ softfloat(Link *ctxt, LSym *cursym) ...@@ -727,7 +729,7 @@ softfloat(Link *ctxt, LSym *cursym)
} }
static Prog* static Prog*
stacksplit(Link *ctxt, Prog *p, int32 framesize) stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
{ {
int32 arg; int32 arg;
...@@ -851,7 +853,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize) ...@@ -851,7 +853,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize)
p->as = ABL; p->as = ABL;
p->scond = C_SCOND_LS; p->scond = C_SCOND_LS;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[0]; p->to.sym = ctxt->symmorestack[noctxt];
// BLS start // BLS start
p = appendp(ctxt, p); p = appendp(ctxt, p);
......
...@@ -342,20 +342,30 @@ static char* ...@@ -342,20 +342,30 @@ static char*
morename[] = morename[] =
{ {
"runtime.morestack00", "runtime.morestack00",
"runtime.morestack00_noctxt",
"runtime.morestack10", "runtime.morestack10",
"runtime.morestack10_noctxt",
"runtime.morestack01", "runtime.morestack01",
"runtime.morestack01_noctxt",
"runtime.morestack11", "runtime.morestack11",
"runtime.morestack11_noctxt",
"runtime.morestack8", "runtime.morestack8",
"runtime.morestack8_noctxt",
"runtime.morestack16", "runtime.morestack16",
"runtime.morestack16_noctxt",
"runtime.morestack24", "runtime.morestack24",
"runtime.morestack24_noctxt",
"runtime.morestack32", "runtime.morestack32",
"runtime.morestack32_noctxt",
"runtime.morestack40", "runtime.morestack40",
"runtime.morestack40_noctxt",
"runtime.morestack48", "runtime.morestack48",
"runtime.morestack48_noctxt",
}; };
static Prog* load_g_cx(Link*, Prog*); static Prog* load_g_cx(Link*, Prog*);
static Prog* stacksplit(Link*, Prog*, int32, int32, Prog**); static Prog* stacksplit(Link*, Prog*, int32, int32, int, Prog**);
static void indir_cx(Link*, Addr*); static void indir_cx(Link*, Addr*);
static void static void
...@@ -419,7 +429,7 @@ addstacksplit(Link *ctxt, LSym *cursym) ...@@ -419,7 +429,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
p = load_g_cx(ctxt, p); // load g into CX p = load_g_cx(ctxt, p); // load g into CX
} }
if(!(cursym->text->from.scale & NOSPLIT)) if(!(cursym->text->from.scale & NOSPLIT))
p = stacksplit(ctxt, p, autoffset, textarg, &q); // emit split check p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
if(autoffset) { if(autoffset) {
if(autoffset%ctxt->arch->regsize != 0) if(autoffset%ctxt->arch->regsize != 0)
...@@ -674,7 +684,7 @@ load_g_cx(Link *ctxt, Prog *p) ...@@ -674,7 +684,7 @@ load_g_cx(Link *ctxt, Prog *p)
// On return, *jmpok is the instruction that should jump // On return, *jmpok is the instruction that should jump
// to the stack frame allocation if no split is needed. // to the stack frame allocation if no split is needed.
static Prog* static Prog*
stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog **jmpok)
{ {
Prog *q, *q1; Prog *q, *q1;
uint32 moreconst1, moreconst2, i; uint32 moreconst1, moreconst2, i;
...@@ -822,7 +832,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) ...@@ -822,7 +832,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok)
if(moreconst1 == 0 && moreconst2 == 0) { if(moreconst1 == 0 && moreconst2 == 0) {
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[0]; p->to.sym = ctxt->symmorestack[0*2+noctxt];
} else } else
if(moreconst1 != 0 && moreconst2 == 0) { if(moreconst1 != 0 && moreconst2 == 0) {
p->as = AMOVL; p->as = AMOVL;
...@@ -833,13 +843,13 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) ...@@ -833,13 +843,13 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok)
p = appendp(ctxt, p); p = appendp(ctxt, p);
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[1]; p->to.sym = ctxt->symmorestack[1*2+noctxt];
} else } else
if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
i = moreconst2/8 + 3; i = moreconst2/8 + 3;
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[i]; p->to.sym = ctxt->symmorestack[i*2+noctxt];
} else } else
if(moreconst1 == 0 && moreconst2 != 0) { if(moreconst1 == 0 && moreconst2 != 0) {
p->as = AMOVL; p->as = AMOVL;
...@@ -850,7 +860,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) ...@@ -850,7 +860,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok)
p = appendp(ctxt, p); p = appendp(ctxt, p);
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[2]; p->to.sym = ctxt->symmorestack[2*2+noctxt];
} else { } else {
p->as = mov; p->as = mov;
p->from.type = D_CONST; p->from.type = D_CONST;
...@@ -861,7 +871,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok) ...@@ -861,7 +871,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, Prog **jmpok)
p = appendp(ctxt, p); p = appendp(ctxt, p);
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[3]; p->to.sym = ctxt->symmorestack[3*2+noctxt];
} }
p = appendp(ctxt, p); p = appendp(ctxt, p);
......
...@@ -256,7 +256,7 @@ prg(void) ...@@ -256,7 +256,7 @@ prg(void)
} }
static Prog* load_g_cx(Link*, Prog*); static Prog* load_g_cx(Link*, Prog*);
static Prog* stacksplit(Link*, Prog*, int32, Prog**); static Prog* stacksplit(Link*, Prog*, int32, int, Prog**);
static void static void
addstacksplit(Link *ctxt, LSym *cursym) addstacksplit(Link *ctxt, LSym *cursym)
...@@ -265,8 +265,10 @@ addstacksplit(Link *ctxt, LSym *cursym) ...@@ -265,8 +265,10 @@ addstacksplit(Link *ctxt, LSym *cursym)
int32 autoffset, deltasp; int32 autoffset, deltasp;
int a; int a;
if(ctxt->symmorestack[0] == nil) if(ctxt->symmorestack[0] == nil) {
ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
}
if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil) if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
ctxt->plan9tos = linklookup(ctxt, "_tos", 0); ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
...@@ -291,7 +293,7 @@ addstacksplit(Link *ctxt, LSym *cursym) ...@@ -291,7 +293,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
p = load_g_cx(ctxt, p); // load g into CX p = load_g_cx(ctxt, p); // load g into CX
} }
if(!(cursym->text->from.scale & NOSPLIT)) if(!(cursym->text->from.scale & NOSPLIT))
p = stacksplit(ctxt, p, autoffset, &q); // emit split check p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
if(autoffset) { if(autoffset) {
p = appendp(ctxt, p); p = appendp(ctxt, p);
...@@ -499,7 +501,7 @@ load_g_cx(Link *ctxt, Prog *p) ...@@ -499,7 +501,7 @@ load_g_cx(Link *ctxt, Prog *p)
// On return, *jmpok is the instruction that should jump // On return, *jmpok is the instruction that should jump
// to the stack frame allocation if no split is needed. // to the stack frame allocation if no split is needed.
static Prog* static Prog*
stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok) stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
{ {
Prog *q, *q1; Prog *q, *q1;
int arg; int arg;
...@@ -642,7 +644,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok) ...@@ -642,7 +644,7 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok)
p = appendp(ctxt, p); p = appendp(ctxt, p);
p->as = ACALL; p->as = ACALL;
p->to.type = D_BRANCH; p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[0]; p->to.sym = ctxt->symmorestack[noctxt];
p = appendp(ctxt, p); p = appendp(ctxt, p);
p->as = AJMP; p->as = AJMP;
......
...@@ -247,6 +247,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 ...@@ -247,6 +247,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL $0, 0x1003 // crash if newstack returns MOVL $0, 0x1003 // crash if newstack returns
RET RET
TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
MOVL $0, DX
JMP runtime·morestack(SB)
// Called from panic. Mimics morestack, // Called from panic. Mimics morestack,
// reuses stack growth code to create a frame // reuses stack growth code to create a frame
// with the desired args running the desired function. // with the desired args running the desired function.
......
...@@ -456,6 +456,46 @@ TEXT morestack<>(SB),NOSPLIT,$0 ...@@ -456,6 +456,46 @@ TEXT morestack<>(SB),NOSPLIT,$0
MOVQ $runtime·morestack(SB), AX MOVQ $runtime·morestack(SB), AX
JMP AX JMP AX
TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack00(SB)
TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack01(SB)
TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack10(SB)
TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack11(SB)
TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack8(SB)
TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack16(SB)
TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack24(SB)
TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack32(SB)
TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack40(SB)
TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack48(SB)
// bool cas(int32 *val, int32 old, int32 new) // bool cas(int32 *val, int32 old, int32 new)
// Atomically: // Atomically:
// if(*val == old){ // if(*val == old){
......
...@@ -437,6 +437,46 @@ TEXT morestack<>(SB),NOSPLIT,$0 ...@@ -437,6 +437,46 @@ TEXT morestack<>(SB),NOSPLIT,$0
MOVL $runtime·morestack(SB), AX MOVL $runtime·morestack(SB), AX
JMP AX JMP AX
TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack00(SB)
TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack01(SB)
TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack10(SB)
TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack11(SB)
TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack8(SB)
TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack16(SB)
TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack24(SB)
TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack32(SB)
TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack40(SB)
TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
MOVL $0, DX
JMP runtime·morestack48(SB)
// bool cas(int32 *val, int32 old, int32 new) // bool cas(int32 *val, int32 old, int32 new)
// Atomically: // Atomically:
// if(*val == old){ // if(*val == old){
......
...@@ -213,6 +213,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0 ...@@ -213,6 +213,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
// is still in this function, and not the beginning of the next. // is still in this function, and not the beginning of the next.
RET RET
TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
MOVW $0, R7
JMP runtime·morestack(SB)
// Called from panic. Mimics morestack, // Called from panic. Mimics morestack,
// reuses stack growth code to create a frame // reuses stack growth code to create a frame
// with the desired args running the desired function. // with the desired args running the desired function.
......
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