aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2011-05-27 11:20:46 -0700
committerRoland Dreier <roland@purestorage.com>2011-05-27 11:20:46 -0700
commit5b0baf05195696eeebc3ef70f7c9218166d33f3b (patch)
treeda6d711d8e5ac52bccca2315513c2f1fcafd04b3
parent03bc2a2304d6f018f3cd1a9fad5e6d0b2c80dd21 (diff)
downloadlibibverbs-5b0baf05195696eeebc3ef70f7c9218166d33f3b.tar.gz
Fix crash if no devices and ibv_get_device_list() is called multiple times
If no devices are found, ibverbs_init() sets num_devices to 0. This means the next call to __ibv_get_device_list() would call ibverbs_init() again, which crashes because ibverbs_init() leaves various internal pointers pointing to freed memory. Fix this by using pthread_once() to call ibverbs_init() exactly once, and then doing the right thing even if num_devices stays 0. Tested-by: Yann Droneaud <ydroneaud@opteya.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--src/device.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/src/device.c b/src/device.c
index 185f4a6..5798895 100644
--- a/src/device.c
+++ b/src/device.c
@@ -49,32 +49,34 @@
#include "ibverbs.h"
-static pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t device_list_once = PTHREAD_ONCE_INIT;
static int num_devices;
static struct ibv_device **device_list;
+static void count_devices(void)
+{
+ num_devices = ibverbs_init(&device_list);
+}
+
struct ibv_device **__ibv_get_device_list(int *num)
{
- struct ibv_device **l = 0;
+ struct ibv_device **l;
int i;
if (num)
*num = 0;
- pthread_mutex_lock(&device_list_lock);
-
- if (!num_devices)
- num_devices = ibverbs_init(&device_list);
+ pthread_once(&device_list_once, count_devices);
if (num_devices < 0) {
errno = -num_devices;
- goto out;
+ return NULL;
}
l = calloc(num_devices + 1, sizeof (struct ibv_device *));
if (!l) {
errno = ENOMEM;
- goto out;
+ return NULL;
}
for (i = 0; i < num_devices; ++i)
@@ -82,8 +84,6 @@ struct ibv_device **__ibv_get_device_list(int *num)
if (num)
*num = num_devices;
-out:
- pthread_mutex_unlock(&device_list_lock);
return l;
}
default_symver(__ibv_get_device_list, ibv_get_device_list);