correct dangling pointer race (Bakul Shah)

This commit is contained in:
rsc 2007-04-08 01:30:26 +00:00
parent 8ecb4ffe4c
commit 4f6d2bb1e8
4 changed files with 36 additions and 6 deletions

View file

@ -46,5 +46,6 @@ vtfreeconn(VtConn *z)
packetfree(z->part); packetfree(z->part);
vtfree(z->version); vtfree(z->version);
vtfree(z->sid); vtfree(z->sid);
qunlock(&z->lk);
vtfree(z); vtfree(z);
} }

View file

@ -12,6 +12,7 @@ struct Qel
struct Queue struct Queue
{ {
int ref;
int hungup; int hungup;
QLock lk; QLock lk;
Rendez r; Rendez r;
@ -26,14 +27,32 @@ _vtqalloc(void)
q = vtmallocz(sizeof(Queue)); q = vtmallocz(sizeof(Queue));
q->r.l = &q->lk; q->r.l = &q->lk;
q->ref = 1;
return q;
}
Queue*
_vtqincref(Queue *q)
{
qlock(&q->lk);
q->ref++;
qunlock(&q->lk);
return q; return q;
} }
void void
_vtqfree(Queue *q) _vtqdecref(Queue *q)
{ {
Qel *e; Qel *e;
qlock(&q->lk);
if(--q->ref > 0){
qunlock(&q->lk);
return;
}
assert(q->ref == 0);
qunlock(&q->lk);
/* Leaks the pointers e->p! */ /* Leaks the pointers e->p! */
while(q->head){ while(q->head){
e = q->head; e = q->head;

View file

@ -4,4 +4,5 @@ int _vtqsend(Queue*, void*);
void *_vtqrecv(Queue*); void *_vtqrecv(Queue*);
void _vtqhangup(Queue*); void _vtqhangup(Queue*);
void *_vtnbqrecv(Queue*); void *_vtnbqrecv(Queue*);
void _vtqfree(Queue*); void _vtqdecref(Queue*);
Queue *_vtqincref(Queue*);

View file

@ -147,7 +147,7 @@ vtrecvproc(void *v)
_vtqhangup(q); _vtqhangup(q);
while((p = _vtnbqrecv(q)) != nil) while((p = _vtnbqrecv(q)) != nil)
packetfree(p); packetfree(p);
_vtqfree(q); _vtqdecref(q);
z->readq = nil; z->readq = nil;
rwakeup(&z->rpcfork); rwakeup(&z->rpcfork);
qunlock(&z->lk); qunlock(&z->lk);
@ -178,7 +178,7 @@ vtsendproc(void *v)
_vtqhangup(q); _vtqhangup(q);
while((p = _vtnbqrecv(q)) != nil) while((p = _vtnbqrecv(q)) != nil)
packetfree(p); packetfree(p);
_vtqfree(q); _vtqdecref(q);
z->writeq = nil; z->writeq = nil;
rwakeup(&z->rpcfork); rwakeup(&z->rpcfork);
qunlock(&z->lk); qunlock(&z->lk);
@ -189,6 +189,7 @@ Packet*
vtrecv(VtConn *z) vtrecv(VtConn *z)
{ {
Packet *p; Packet *p;
Queue *q;
qlock(&z->lk); qlock(&z->lk);
if(z->state != VtStateConnected){ if(z->state != VtStateConnected){
@ -197,8 +198,11 @@ vtrecv(VtConn *z)
return nil; return nil;
} }
if(z->readq){ if(z->readq){
q = _vtqincref(z->readq);
qunlock(&z->lk); qunlock(&z->lk);
return _vtqrecv(z->readq); p = _vtqrecv(q);
_vtqdecref(q);
return p;
} }
qlock(&z->inlk); qlock(&z->inlk);
@ -213,6 +217,8 @@ vtrecv(VtConn *z)
int int
vtsend(VtConn *z, Packet *p) vtsend(VtConn *z, Packet *p)
{ {
Queue *q;
qlock(&z->lk); qlock(&z->lk);
if(z->state != VtStateConnected){ if(z->state != VtStateConnected){
packetfree(p); packetfree(p);
@ -221,11 +227,14 @@ vtsend(VtConn *z, Packet *p)
return -1; return -1;
} }
if(z->writeq){ if(z->writeq){
q = _vtqincref(z->writeq);
qunlock(&z->lk); qunlock(&z->lk);
if(_vtqsend(z->writeq, p) < 0){ if(_vtqsend(q, p) < 0){
_vtqdecref(q);
packetfree(p); packetfree(p);
return -1; return -1;
} }
_vtqdecref(q);
return 0; return 0;
} }