Check for overflow of VArray size
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/79c0784a Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/79c0784a Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/79c0784a Branch: refs/heads/master Commit: 79c0784ab0b37d384b7d6830579f2f80f7c47a97 Parents: b3132fb Author: Nick Wellnhofer <[email protected]> Authored: Tue Nov 11 20:52:03 2014 +0100 Committer: Nick Wellnhofer <[email protected]> Committed: Tue Nov 11 20:54:35 2014 +0100 ---------------------------------------------------------------------- runtime/core/Clownfish/Test/TestVArray.c | 61 ++++++++++++++++++++++++++- runtime/core/Clownfish/VArray.c | 34 +++++++++++---- 2 files changed, 85 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/79c0784a/runtime/core/Clownfish/Test/TestVArray.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/Test/TestVArray.c b/runtime/core/Clownfish/Test/TestVArray.c index f817944..923d637 100644 --- a/runtime/core/Clownfish/Test/TestVArray.c +++ b/runtime/core/Clownfish/Test/TestVArray.c @@ -16,6 +16,7 @@ #include <string.h> +#define C_CFISH_VARRAY #define CFISH_USE_SHORT_NAMES #define TESTCFISH_USE_SHORT_NAMES @@ -293,9 +294,66 @@ test_Clone_and_Shallow_Copy(TestBatchRunner *runner) { DECREF(twin); } +static void +S_overflow_Push(void *context) { + UNUSED_VAR(context); + VArray *array = VA_new(0); + array->cap = UINT32_MAX; + array->size = array->cap; + VA_Push(array, (Obj*)CFISH_TRUE); +} + +static void +S_overflow_Unshift(void *context) { + UNUSED_VAR(context); + VArray *array = VA_new(0); + array->cap = UINT32_MAX; + array->size = array->cap; + VA_Unshift(array, (Obj*)CFISH_TRUE); +} + +static void +S_overflow_Push_VArray(void *context) { + UNUSED_VAR(context); + VArray *array = VA_new(0); + array->cap = 1000000000; + array->size = array->cap; + VArray *other = VA_new(0); + other->cap = UINT32_MAX - array->cap + 1; + other->size = other->cap; + VA_Push_VArray(array, other); +} + +static void +S_overflow_Store(void *context) { + UNUSED_VAR(context); + VArray *array = VA_new(0); + VA_Store(array, UINT32_MAX, (Obj*)CFISH_TRUE); +} + +static void +S_test_exception(TestBatchRunner *runner, Err_Attempt_t func, + const char *test_name) { + Err *error = Err_trap(func, NULL); + TEST_TRUE(runner, error != NULL, test_name); + DECREF(error); +} + +static void +test_exceptions(TestBatchRunner *runner) { + S_test_exception(runner, S_overflow_Push, + "Push throws on overflow"); + S_test_exception(runner, S_overflow_Unshift, + "Unshift throws on overflow"); + S_test_exception(runner, S_overflow_Push_VArray, + "Push_VArray throws on overflow"); + S_test_exception(runner, S_overflow_Store, + "Store throws on overflow"); +} + void TestVArray_Run_IMP(TestVArray *self, TestBatchRunner *runner) { - TestBatchRunner_Plan(runner, (TestBatch*)self, 43); + TestBatchRunner_Plan(runner, (TestBatch*)self, 47); test_Equals(runner); test_Store_Fetch(runner); test_Push_Pop_Shift_Unshift(runner); @@ -305,6 +363,7 @@ TestVArray_Run_IMP(TestVArray *self, TestBatchRunner *runner) { test_Push_VArray(runner); test_Slice(runner); test_Clone_and_Shallow_Copy(runner); + test_exceptions(runner); } http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/79c0784a/runtime/core/Clownfish/VArray.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/VArray.c b/runtime/core/Clownfish/VArray.c index 2472084..b6170d3 100644 --- a/runtime/core/Clownfish/VArray.c +++ b/runtime/core/Clownfish/VArray.c @@ -26,6 +26,9 @@ #include "Clownfish/Util/Memory.h" #include "Clownfish/Util/SortUtils.h" +static CFISH_INLINE void +SI_grow_by(VArray *self, uint32_t add_size); + VArray* VA_new(uint32_t capacity) { VArray *self = (VArray*)Class_Make_Obj(VARRAY); @@ -97,7 +100,7 @@ VA_Shallow_Copy_IMP(VArray *self) { void VA_Push_IMP(VArray *self, Obj *element) { if (self->size == self->cap) { - VA_Grow(self, Memory_oversize(self->size + 1, sizeof(Obj*))); + SI_grow_by(self, 1); } self->elems[self->size] = element; self->size++; @@ -105,18 +108,16 @@ VA_Push_IMP(VArray *self, Obj *element) { void VA_Push_VArray_IMP(VArray *self, VArray *other) { - uint32_t tick = self->size; - uint32_t new_size = self->size + other->size; - if (new_size > self->cap) { - VA_Grow(self, Memory_oversize(new_size, sizeof(Obj*))); + if (other->size > self->cap - self->size) { + SI_grow_by(self, other->size); } - for (uint32_t i = 0; i < other->size; i++, tick++) { + for (uint32_t i = 0, tick = self->size; i < other->size; i++, tick++) { Obj *elem = VA_Fetch(other, i); if (elem != NULL) { self->elems[tick] = INCREF(elem); } } - self->size = new_size; + self->size += other->size; } Obj* @@ -131,7 +132,7 @@ VA_Pop_IMP(VArray *self) { void VA_Unshift_IMP(VArray *self, Obj *elem) { if (self->size == self->cap) { - VA_Grow(self, Memory_oversize(self->size + 1, sizeof(Obj*))); + SI_grow_by(self, 1); } memmove(self->elems + 1, self->elems, self->size * sizeof(Obj*)); self->elems[0] = elem; @@ -166,7 +167,10 @@ VA_Fetch_IMP(VArray *self, uint32_t num) { void VA_Store_IMP(VArray *self, uint32_t tick, Obj *elem) { if (tick >= self->cap) { - VA_Grow(self, Memory_oversize(tick + 1, sizeof(Obj*))); + if (tick == UINT32_MAX) { + THROW(ERR, "Invalid tick"); + } + SI_grow_by(self, tick + 1 - self->size); } if (tick < self->size) { DECREF(self->elems[tick]); } else { self->size = tick + 1; } @@ -307,3 +311,15 @@ VA_Slice_IMP(VArray *self, uint32_t offset, uint32_t length) { return slice; } +static void +SI_grow_by(VArray *self, uint32_t add_size) { + size_t min_size = self->size + add_size; + // Check for overflow. + if ((uint32_t)min_size < add_size) { + THROW(ERR, "Array grew too large"); + } + size_t new_size = Memory_oversize(min_size, sizeof(Obj*)); + if (new_size > UINT32_MAX) { new_size = UINT32_MAX; } + VA_Grow(self, (uint32_t)new_size); +} +
