ck_array: Fix use-after-free on transactional put.

ck_pring
Samy Al Bahra 11 years ago
parent b801ec4b98
commit 7a49725b7f

@ -141,6 +141,18 @@ main(void)
if (ck_array_initialized(&array) == false) if (ck_array_initialized(&array) == false)
ck_error("Error, expected array to be initialized.\n"); ck_error("Error, expected array to be initialized.\n");
for (i = 0; i < ITERATION * 4; i++) {
ck_array_remove(&array, (void *)i);
}
for (i = 0; i < ITERATION * 2; i++) {
ck_array_put(&array, (void *)i);
}
for (i = 0; i < ITERATION * 8; i++) {
ck_array_put(&array, (void *)i);
}
ck_array_deinit(&array, false); ck_array_deinit(&array, false);
if (ck_array_initialized(&array) == true) if (ck_array_initialized(&array) == true)

@ -72,7 +72,8 @@ ck_array_init(struct ck_array *array, unsigned int mode, struct ck_malloc *alloc
bool bool
ck_array_put(struct ck_array *array, void *value) ck_array_put(struct ck_array *array, void *value)
{ {
struct _ck_array *target, *update; struct _ck_array *target;
unsigned int size;
/* /*
* If no transaction copy has been necessary, attempt to do in-place * If no transaction copy has been necessary, attempt to do in-place
@ -82,23 +83,21 @@ ck_array_put(struct ck_array *array, void *value)
target = array->active; target = array->active;
if (array->n_entries == target->length) { if (array->n_entries == target->length) {
unsigned int size = target->length << 1; size = target->length << 1;
target = array->allocator->realloc(target,
sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
sizeof(struct _ck_array) + sizeof(void *) * size,
true);
update = ck_array_create(array->allocator, size); if (target == NULL)
if (update == NULL)
return false; return false;
memcpy(update->values, target->values, sizeof(void *) * array->n_entries); ck_pr_store_uint(&target->length, size);
update->n_committed = target->n_committed;
update->length = size;
/* Serialize with respect to update contents. */ /* Serialize with respect to contents. */
ck_pr_fence_store(); ck_pr_fence_store();
ck_pr_store_ptr(&array->active, update); ck_pr_store_ptr(&array->active, target);
array->allocator->free(target,
sizeof(struct _ck_array) + target->length * sizeof(void *), true);
target = update;
} }
target->values[array->n_entries++] = value; target->values[array->n_entries++] = value;
@ -107,19 +106,18 @@ ck_array_put(struct ck_array *array, void *value)
target = array->transaction; target = array->transaction;
if (array->n_entries == target->length) { if (array->n_entries == target->length) {
unsigned int size = target->length << 1; size = target->length << 1;
update = array->allocator->realloc(array->transaction, target = array->allocator->realloc(target,
sizeof(struct _ck_array) + sizeof(void *) * array->n_entries, sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
sizeof(struct _ck_array) + sizeof(void *) * size, sizeof(struct _ck_array) + sizeof(void *) * size,
true); true);
if (update == NULL) if (target == NULL)
return false; return false;
update->n_committed = target->n_committed; target->length = size;
update->length = size; array->transaction = target;
array->transaction = update;
} }
target->values[array->n_entries++] = value; target->values[array->n_entries++] = value;
@ -189,9 +187,8 @@ ck_array_remove(struct ck_array *array, void *value)
* transactional array which will be applied upon commit time. * transactional array which will be applied upon commit time.
*/ */
target = ck_array_create(array->allocator, array->n_entries); target = ck_array_create(array->allocator, array->n_entries);
if (target == NULL) { if (target == NULL)
return false; return false;
}
memcpy(target->values, array->active->values, sizeof(void *) * array->n_entries); memcpy(target->values, array->active->values, sizeof(void *) * array->n_entries);
target->length = array->n_entries; target->length = array->n_entries;

Loading…
Cancel
Save