More rework of Vector oversizing Reduce number of overflow checks. Make sure that array size doesn't overflow just because of oversizing.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/6090c315 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/6090c315 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/6090c315 Branch: refs/heads/master Commit: 6090c3153a0d7680117140e25332e243021e15db Parents: c91a9e4 Author: Nick Wellnhofer <wellnho...@aevum.de> Authored: Tue Jul 14 15:17:27 2015 +0200 Committer: Nick Wellnhofer <wellnho...@aevum.de> Committed: Tue Jul 14 15:25:43 2015 +0200 ---------------------------------------------------------------------- runtime/core/Clownfish/Test/TestVector.c | 22 +++++++++---- runtime/core/Clownfish/Vector.c | 47 ++++++++++++--------------- 2 files changed, 37 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/6090c315/runtime/core/Clownfish/Test/TestVector.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVector.c b/runtime/core/Clownfish/Test/TestVector.c index 1a72768..7b51cb3 100644 --- a/runtime/core/Clownfish/Test/TestVector.c +++ b/runtime/core/Clownfish/Test/TestVector.c @@ -21,6 +21,8 @@ #define CFISH_USE_SHORT_NAMES #define TESTCFISH_USE_SHORT_NAMES +#define MAX_VECTOR_SIZE (SIZE_MAX / sizeof(Obj*)) + #include "Clownfish/Test/TestVector.h" #include "Clownfish/String.h" @@ -406,7 +408,7 @@ static void S_overflow_Push(void *context) { UNUSED_VAR(context); Vector *array = Vec_new(0); - array->cap = SIZE_MAX; + array->cap = MAX_VECTOR_SIZE; array->size = array->cap; Vec_Push(array, (Obj*)CFISH_TRUE); } @@ -415,9 +417,7 @@ static void S_overflow_Insert(void *context) { UNUSED_VAR(context); Vector *array = Vec_new(0); - array->cap = SIZE_MAX; - array->size = array->cap; - Vec_Insert(array, 38911, (Obj*)CFISH_TRUE); + Vec_Insert(array, SIZE_MAX, (Obj*)CFISH_TRUE); } static void @@ -427,12 +427,20 @@ S_overflow_Push_All(void *context) { array->cap = 1000000000; array->size = array->cap; Vector *other = Vec_new(0); - other->cap = SIZE_MAX - array->cap + 1; + other->cap = MAX_VECTOR_SIZE - array->cap + 1; other->size = other->cap; Vec_Push_All(array, other); } static void +S_overflow_Insert_All(void *context) { + UNUSED_VAR(context); + Vector *array = Vec_new(0); + Vector *other = Vec_new(0); + Vec_Insert_All(array, SIZE_MAX, other); +} + +static void S_overflow_Store(void *context) { UNUSED_VAR(context); Vector *array = Vec_new(0); @@ -459,6 +467,8 @@ test_exceptions(TestBatchRunner *runner) { "Insert throws on overflow"); S_test_exception(runner, S_overflow_Push_All, "Push_All throws on overflow"); + S_test_exception(runner, S_overflow_Insert_All, + "Insert_All throws on overflow"); S_test_exception(runner, S_overflow_Store, "Store throws on overflow"); } @@ -517,7 +527,7 @@ test_Grow(TestBatchRunner *runner) { void TestVector_Run_IMP(TestVector *self, TestBatchRunner *runner) { - TestBatchRunner_Plan(runner, (TestBatch*)self, 61); + TestBatchRunner_Plan(runner, (TestBatch*)self, 62); test_Equals(runner); test_Store_Fetch(runner); test_Push_Pop_Insert(runner); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/6090c315/runtime/core/Clownfish/Vector.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Vector.c b/runtime/core/Clownfish/Vector.c index 8dbf3cc..18c09d2 100644 --- a/runtime/core/Clownfish/Vector.c +++ b/runtime/core/Clownfish/Vector.c @@ -26,18 +26,17 @@ #include "Clownfish/Util/Memory.h" #include "Clownfish/Util/SortUtils.h" +#define MAX_VECTOR_SIZE (SIZE_MAX / sizeof(Obj*)) + static CFISH_INLINE void SI_copy_and_incref(Obj **dst, Obj **src, size_t num); static CFISH_INLINE void -SI_add_grow_and_oversize(Vector *self, size_t addend1, size_t addend2); +SI_add_grow_and_oversize(Vector *self, size_t size, size_t extra); static void S_grow_and_oversize(Vector *self, size_t min_size); -static CFISH_INLINE void -SI_grow(Vector *self, size_t capacity); - static void S_overflow_error(void); @@ -110,7 +109,7 @@ Vec_Pop_IMP(Vector *self) { void Vec_Insert_IMP(Vector *self, size_t tick, Obj *elem) { size_t max_tick = tick > self->size ? tick : self->size; - SI_add_grow_and_oversize(self, max_tick, 1); + SI_add_grow_and_oversize(self, 1, max_tick); if (tick < self->size) { memmove(self->elems + tick + 1, self->elems + tick, @@ -128,7 +127,7 @@ Vec_Insert_IMP(Vector *self, size_t tick, Obj *elem) { void Vec_Insert_All_IMP(Vector *self, size_t tick, Vector *other) { size_t max_tick = tick > self->size ? tick : self->size; - SI_add_grow_and_oversize(self, max_tick, other->size); + SI_add_grow_and_oversize(self, other->size, max_tick); if (tick < self->size) { memmove(self->elems + tick + other->size, self->elems + tick, @@ -158,7 +157,7 @@ Vec_Store_IMP(Vector *self, size_t tick, Obj *elem) { DECREF(self->elems[tick]); } else { - SI_add_grow_and_oversize(self, tick, 1); + SI_add_grow_and_oversize(self, 1, tick); memset(self->elems + self->size, 0, (tick - self->size) * sizeof(Obj*)); self->size = tick + 1; @@ -169,7 +168,12 @@ Vec_Store_IMP(Vector *self, size_t tick, Obj *elem) { void Vec_Grow_IMP(Vector *self, size_t capacity) { if (capacity > self->cap) { - SI_grow(self, capacity); + if (capacity > MAX_VECTOR_SIZE) { + S_overflow_error(); + return; + } + self->elems = (Obj**)REALLOCATE(self->elems, capacity * sizeof(Obj*)); + self->cap = capacity; } } @@ -301,22 +305,24 @@ SI_copy_and_incref(Obj **dst, Obj **src, size_t num) { } } -// Ensure that the vector's capacity is at least (addend1 + addend2). +// Ensure that the vector's capacity is at least (size + extra). +// Assumes that size <= MAX_VECTOR_SIZE. // If the vector must be grown, oversize the allocation. static CFISH_INLINE void -SI_add_grow_and_oversize(Vector *self, size_t addend1, size_t addend2) { - size_t min_size = addend1 + addend2; - // Check for overflow. - if (min_size < addend1) { +SI_add_grow_and_oversize(Vector *self, size_t size, size_t extra) { + if (extra > MAX_VECTOR_SIZE - size) { S_overflow_error(); return; } + size_t min_size = size + extra; if (min_size > self->cap) { S_grow_and_oversize(self, min_size); } } +// Assumes min_size <= MAX_VECTOR_SIZE. +// __attribute__((noinline)) static void S_grow_and_oversize(Vector *self, size_t min_size) { // Oversize by 25%, but at least four elements. @@ -324,21 +330,10 @@ S_grow_and_oversize(Vector *self, size_t min_size) { if (extra < 4) { extra = 4; } size_t capacity = min_size + extra; - // Check for overflow. - if (capacity < min_size) { - S_overflow_error(); - return; + if (capacity > MAX_VECTOR_SIZE) { + capacity = MAX_VECTOR_SIZE; } - SI_grow(self, capacity); -} - -static CFISH_INLINE void -SI_grow(Vector *self, size_t capacity) { - if (capacity > SIZE_MAX / sizeof(Obj*)) { - S_overflow_error(); - return; - } self->elems = (Obj**)REALLOCATE(self->elems, capacity * sizeof(Obj*)); self->cap = capacity; }