diff options
author | dimitri staessens <dimitri.staessens@intec.ugent.be> | 2016-12-28 09:05:44 +0100 |
---|---|---|
committer | dimitri staessens <dimitri.staessens@intec.ugent.be> | 2016-12-28 09:15:46 +0100 |
commit | 502e7bb39096f6ce7718c29d9616bbd0314d045e (patch) | |
tree | cfa8af4328890f3534adc17c1f1ee8be67331cc3 | |
parent | 6d14473d4fd0629125d9a96d9292deb32ba7e0a8 (diff) | |
download | ouroboros-502e7bb39096f6ce7718c29d9616bbd0314d045e.tar.gz ouroboros-502e7bb39096f6ce7718c29d9616bbd0314d045e.zip |
lib: Fix race in destruction of cdap_req
If cdap_req_destroy was called while in REQ_DONE, cdap->state would be
accessed in cdap_req_respond.
-rw-r--r-- | src/lib/cdap_req.c | 25 | ||||
-rw-r--r-- | src/lib/cdap_req.h | 3 |
2 files changed, 18 insertions, 10 deletions
diff --git a/src/lib/cdap_req.c b/src/lib/cdap_req.c index f80b10d7..57ad22c5 100644 --- a/src/lib/cdap_req.c +++ b/src/lib/cdap_req.c @@ -70,14 +70,14 @@ void cdap_req_destroy(struct cdap_req * creq) } if (creq->state == REQ_INIT) - creq->state = REQ_DONE; + creq->state = REQ_NULL; if (creq->state == REQ_PENDING) { creq->state = REQ_DESTROY; pthread_cond_broadcast(&creq->cond); } - while (creq->state != REQ_DONE) + while (creq->state != REQ_NULL) pthread_cond_wait(&creq->cond, &creq->lock); pthread_mutex_unlock(&creq->lock); @@ -109,17 +109,21 @@ int cdap_req_wait(struct cdap_req * creq) creq->state = REQ_PENDING; while (creq->state == REQ_PENDING) { - if ((ret = -pthread_cond_timedwait(&creq->cond, - &creq->lock, - &abstime)) == -ETIMEDOUT) + ret = -pthread_cond_timedwait(&creq->cond, + &creq->lock, + &abstime); + if (ret == -ETIMEDOUT) break; } - if (creq->state == REQ_DESTROY) + if (creq->state == REQ_DESTROY) { ret = -1; - - creq->state = REQ_DONE; - pthread_cond_broadcast(&creq->cond); + creq->state = REQ_NULL; + pthread_cond_broadcast(&creq->cond); + } else { + creq->state = REQ_DONE; + pthread_cond_broadcast(&creq->cond); + } pthread_mutex_unlock(&creq->lock); @@ -146,5 +150,8 @@ void cdap_req_respond(struct cdap_req * creq, int response, buffer_t data) while (creq->state == REQ_RESPONSE) pthread_cond_wait(&creq->cond, &creq->lock); + creq->state = REQ_NULL; + pthread_cond_broadcast(&creq->cond); + pthread_mutex_unlock(&creq->lock); } diff --git a/src/lib/cdap_req.h b/src/lib/cdap_req.h index 9d5cb0c8..b2ded060 100644 --- a/src/lib/cdap_req.h +++ b/src/lib/cdap_req.h @@ -31,7 +31,8 @@ #include <pthread.h> enum creq_state { - REQ_INIT = 0, + REQ_NULL = 0, + REQ_INIT, REQ_PENDING, REQ_RESPONSE, REQ_DONE, |