Commit b89d6309 authored by Adam Langley's avatar Adam Langley

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
parent b691e08e
......@@ -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;
}
......
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