Fix bug when sending via select.

selfree maintains a cache of Select structures for several sizes. In
newselect, we'll use an entry from the cache if one is found. However,
the Scase structures corresponding to a send may have been allocated
for the wrong size. In this case we'll write off the end of the Scase
into random memory and, generally, read some amount of junk in the
receive.

This patch fixes the issue by removing the cache, on the advice of
rsc.

R=rsc
CC=go-dev
http://go/go-review/1016002
This commit is contained in:
Adam Langley 2009-10-28 18:23:53 -07:00
parent b691e08e2c
commit b89d630977

View File

@ -79,8 +79,6 @@ struct Select
Scase* scase[1]; // one per case
};
static Select* selfree[20];
static SudoG* dequeue(WaitQ*, Hchan*);
static void enqueue(WaitQ*, SudoG*);
static SudoG* allocsg(Hchan*);
@ -446,16 +444,7 @@ runtime·newselect(int32 size, ...)
if(size > 1)
n = size-1;
lock(&chanlock);
sel = nil;
if(size >= 1 && size < nelem(selfree)) {
sel = selfree[size];
if(sel != nil)
selfree[size] = sel->link;
}
unlock(&chanlock);
if(sel == nil)
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
sel->tcase = size;
sel->ncase = 0;
@ -485,11 +474,8 @@ runtime·selectsend(Select *sel, Hchan *c, ...)
if(i >= sel->tcase)
throw("selectsend: too many cases");
sel->ncase = i+1;
cas = sel->scase[i];
if(cas == nil) {
cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
sel->scase[i] = cas;
}
cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
sel->scase[i] = cas;
cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
@ -509,7 +495,7 @@ runtime·selectsend(Select *sel, Hchan *c, ...)
runtime·printpointer(cas->pc);
prints(" chan=");
runtime·printpointer(cas->chan);
prints(" po=");
prints(" so=");
runtime·printint(cas->so);
prints(" send=");
runtime·printint(cas->send);
@ -532,11 +518,8 @@ runtime·selectrecv(Select *sel, Hchan *c, ...)
if(i >= sel->tcase)
throw("selectrecv: too many cases");
sel->ncase = i+1;
cas = sel->scase[i];
if(cas == nil) {
cas = mal(sizeof *cas);
sel->scase[i] = cas;
}
cas = mal(sizeof *cas);
sel->scase[i] = cas;
cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
@ -573,11 +556,8 @@ runtime·selectdefault(Select *sel, ...)
if(i >= sel->tcase)
throw("selectdefault: too many cases");
sel->ncase = i+1;
cas = sel->scase[i];
if(cas == nil) {
cas = mal(sizeof *cas);
sel->scase[i] = cas;
}
cas = mal(sizeof *cas);
sel->scase[i] = cas;
cas->pc = runtime·getcallerpc(&sel);
cas->chan = nil;
@ -598,6 +578,16 @@ runtime·selectdefault(Select *sel, ...)
}
}
static void
freesel(Select *sel)
{
uint32 i;
for(i=0; i<sel->ncase; i++)
free(sel->scase[i]);
free(sel);
}
// selectgo(sel *byte);
void
runtime·selectgo(Select *sel)
@ -863,14 +853,11 @@ sclose:
goto retc;
retc:
if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
sel->link = selfree[sel->ncase];
selfree[sel->ncase] = sel;
}
unlock(&chanlock);
runtime·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
freesel(sel);
*as = true;
}