builtin: fix arrays/slices memory bug (#10219)

pull/10225/head
Uwe Krüger 2021-05-27 14:50:06 +02:00 committed by GitHub
parent 25645dbc44
commit 8828054e5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 13 deletions

View File

@ -11,6 +11,7 @@ pub:
element_size int // size in bytes of one element in the array.
pub mut:
data voidptr
offset int // in bytes (should be `size_t`)
len int // length of the array.
cap int // capacity of the array.
}
@ -95,11 +96,13 @@ fn (mut a array) ensure_cap(required int) {
cap *= 2
}
new_size := cap * a.element_size
a.data = if a.data != voidptr(0) {
unsafe { realloc_data(a.data, a.cap * a.element_size, new_size) }
} else {
vcalloc(new_size)
new_data := vcalloc(new_size)
if a.data != voidptr(0) {
unsafe { C.memcpy(new_data, a.data, a.len * a.element_size) }
// TODO: the old data may be leaked when no GC is used (ref-counting?)
}
a.data = new_data
a.offset = 0
a.cap = cap
}
@ -307,14 +310,13 @@ fn (a array) slice(start int, _end int) array {
panic('array.slice: slice bounds out of range ($start < 0)')
}
}
mut data := &byte(0)
unsafe {
data = &byte(a.data) + start * a.element_size
}
offset := start * a.element_size
data := unsafe { &byte(a.data) + offset }
l := end - start
res := array{
element_size: a.element_size
data: data
offset: a.offset + offset
len: l
cap: l
}
@ -384,13 +386,15 @@ fn (a &array) slice_clone(start int, _end int) array {
}
}
mut data := &byte(0)
offset := start * a.element_size
unsafe {
data = &byte(a.data) + start * a.element_size
data = &byte(a.data) + offset
}
l := end - start
res := array{
element_size: a.element_size
data: data
offset: offset
len: l
cap: l
}
@ -484,7 +488,7 @@ pub fn (a &array) free() {
// if a.is_slice {
// return
// }
unsafe { free(a.data) }
unsafe { free(&byte(a.data) - a.offset) }
}
[unsafe]

View File

@ -60,3 +60,22 @@ fn test_pointer_array_slice() {
mut arr := [1, 2, 3]
pointer_array_slice(mut arr)
}
fn test_push_to_orig() {
mut orig := [1, 2, 3, 4]
slice := orig[1..3]
for _ in 0 .. 1000 {
orig << 9
}
orig[2] = 7
slice2 := orig[1..3]
assert slice == [2, 3] || slice == [2, 7]
assert slice2 == [2, 7]
}
fn test_self_slice_push() {
mut a := [1, 2, 3]
a = a[1..]
a << 4
assert a == [2, 3, 4]
}