summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--tests/custom/03_bugs/26_invalid_sparse_array_set49
-rw-r--r--types.c10
2 files changed, 57 insertions, 2 deletions
diff --git a/tests/custom/03_bugs/26_invalid_sparse_array_set b/tests/custom/03_bugs/26_invalid_sparse_array_set
new file mode 100644
index 0000000..4c47039
--- /dev/null
+++ b/tests/custom/03_bugs/26_invalid_sparse_array_set
@@ -0,0 +1,49 @@
+When setting an array index which is beyond the end of the last currently
+preallocated chunk and not evenly divisible by the chunk size, the array
+entries list was not properly reallocated resulting in invalid memory
+writes.
+
+-- Testcase --
+{%
+ for (i = 0; i < 32; i++) {
+ a = [];
+ a[i] = true;
+ print(length(a), "\n");
+ }
+%}
+-- End --
+
+-- Expect stdout --
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+-- End --
diff --git a/types.c b/types.c
index b8ad8da..de904ef 100644
--- a/types.c
+++ b/types.c
@@ -701,15 +701,21 @@ bool
ucv_array_set(uc_value_t *uv, size_t index, uc_value_t *item)
{
uc_array_t *array = (uc_array_t *)uv;
- size_t old_count;
+ size_t old_count, new_count;
if (ucv_type(uv) != UC_ARRAY)
return false;
if (index >= array->count) {
old_count = array->count;
+ new_count = (index + 1) & ~(UC_VECTOR_CHUNK_SIZE - 1);
+
+ if (new_count > old_count) {
+ array->count = new_count;
+ uc_vector_grow(array);
+ }
+
array->count = index + 1;
- uc_vector_grow(array);
while (old_count < array->count)
array->entries[old_count++] = NULL;