mirror of
https://github.com/golang/go.git
synced 2024-09-30 14:57:10 +00:00
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:
parent
b691e08e2c
commit
b89d630977
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user