builtin: fix arrays/slices memory bug (#10219)
parent
25645dbc44
commit
8828054e5b
|
@ -10,9 +10,10 @@ pub struct array {
|
|||
pub:
|
||||
element_size int // size in bytes of one element in the array.
|
||||
pub mut:
|
||||
data voidptr
|
||||
len int // length of the array.
|
||||
cap int // capacity of the array.
|
||||
data voidptr
|
||||
offset int // in bytes (should be `size_t`)
|
||||
len int // length of the array.
|
||||
cap int // capacity of the array.
|
||||
}
|
||||
|
||||
// array.data uses a void pointer, which allows implementing arrays without generics and without generating
|
||||
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue