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