summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-09-21 20:24:05 +0200
committerJo-Philipp Wich <jo@mein.io>2021-09-21 20:25:46 +0200
commit914f54cc61e6b16005cceb9562289be0c80e401b (patch)
treed005f3dfaf20df1d2c417998e3d3f395ff80438a
parent631f00df1189550cca923c3d08885e6a7208d542 (diff)
types: fix invalid memory access on setting non-contiguous array indexes
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. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-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;