mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 14:18:47 +00:00
Merge pull request #5344 from Feoramund/fix-2694
Review `core/mem/allocators.odin`
This commit is contained in:
@@ -67,7 +67,7 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a
|
|||||||
// Prefer the procedure group `copy`.
|
// Prefer the procedure group `copy`.
|
||||||
@builtin
|
@builtin
|
||||||
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||||
n := max(0, min(len(dst), len(src)))
|
n := min(len(dst), len(src))
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E))
|
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E))
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
|||||||
// Prefer the procedure group `copy`.
|
// Prefer the procedure group `copy`.
|
||||||
@builtin
|
@builtin
|
||||||
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||||
n := max(0, min(len(dst), len(src)))
|
n := min(len(dst), len(src))
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n)
|
intrinsics.mem_copy(raw_data(dst), raw_data(src), n)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
import "base:sanitizer"
|
// import "base:sanitizer"
|
||||||
|
|
||||||
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE)
|
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE)
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
|
|||||||
block.base = ([^]byte)(uintptr(block) + base_offset)
|
block.base = ([^]byte)(uintptr(block) + base_offset)
|
||||||
block.capacity = uint(end - uintptr(block.base))
|
block.capacity = uint(end - uintptr(block.base))
|
||||||
|
|
||||||
sanitizer.address_poison(block.base, block.capacity)
|
// sanitizer.address_poison(block.base, block.capacity)
|
||||||
|
|
||||||
// Should be zeroed
|
// Should be zeroed
|
||||||
assert(block.used == 0)
|
assert(block.used == 0)
|
||||||
@@ -55,7 +55,7 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
|
|||||||
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
|
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) {
|
||||||
if block_to_free != nil {
|
if block_to_free != nil {
|
||||||
allocator := block_to_free.allocator
|
allocator := block_to_free.allocator
|
||||||
sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
|
// sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
|
||||||
mem_free(block_to_free, allocator, loc)
|
mem_free(block_to_free, allocator, loc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
data = block.base[block.used+alignment_offset:][:min_size]
|
data = block.base[block.used+alignment_offset:][:min_size]
|
||||||
sanitizer.address_unpoison(block.base[block.used:block.used+size])
|
// sanitizer.address_unpoison(block.base[block.used:block.used+size])
|
||||||
block.used += size
|
block.used += size
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
|||||||
if arena.curr_block != nil {
|
if arena.curr_block != nil {
|
||||||
intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used)
|
intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used)
|
||||||
arena.curr_block.used = 0
|
arena.curr_block.used = 0
|
||||||
sanitizer.address_poison(arena.curr_block.base, arena.curr_block.capacity)
|
// sanitizer.address_poison(arena.curr_block.base, arena.curr_block.capacity)
|
||||||
}
|
}
|
||||||
arena.total_used = 0
|
arena.total_used = 0
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
// grow data in-place, adjusting next allocation
|
// grow data in-place, adjusting next allocation
|
||||||
block.used = uint(new_end)
|
block.used = uint(new_end)
|
||||||
data = block.base[start:new_end]
|
data = block.base[start:new_end]
|
||||||
sanitizer.address_unpoison(data)
|
// sanitizer.address_unpoison(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,7 +306,7 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
|||||||
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||||
amount_to_zero := block.used-temp.used
|
amount_to_zero := block.used-temp.used
|
||||||
intrinsics.mem_zero(block.base[temp.used:], amount_to_zero)
|
intrinsics.mem_zero(block.base[temp.used:], amount_to_zero)
|
||||||
sanitizer.address_poison(block.base[temp.used:block.capacity])
|
// sanitizer.address_poison(block.base[temp.used:block.capacity])
|
||||||
block.used = temp.used
|
block.used = temp.used
|
||||||
arena.total_used -= amount_to_zero
|
arena.total_used -= amount_to_zero
|
||||||
}
|
}
|
||||||
|
|||||||
+347
-223
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
package mem
|
package mem
|
||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
import "base:sanitizer"
|
// import "base:sanitizer"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Rollback stack default block size.
|
Rollback stack default block size.
|
||||||
@@ -134,7 +134,7 @@ rb_free_all :: proc(stack: ^Rollback_Stack) {
|
|||||||
stack.head.next_block = nil
|
stack.head.next_block = nil
|
||||||
stack.head.last_alloc = nil
|
stack.head.last_alloc = nil
|
||||||
stack.head.offset = 0
|
stack.head.offset = 0
|
||||||
sanitizer.address_poison(stack.head.buffer)
|
// sanitizer.address_poison(stack.head.buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -241,7 +241,7 @@ rb_alloc_bytes_non_zeroed :: proc(
|
|||||||
block.offset = cast(uintptr)len(block.buffer)
|
block.offset = cast(uintptr)len(block.buffer)
|
||||||
}
|
}
|
||||||
res := ptr[:size]
|
res := ptr[:size]
|
||||||
sanitizer.address_unpoison(res)
|
// sanitizer.address_unpoison(res)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
@@ -338,7 +338,7 @@ rb_resize_bytes_non_zeroed :: proc(
|
|||||||
block.offset += cast(uintptr)size - cast(uintptr)old_size
|
block.offset += cast(uintptr)size - cast(uintptr)old_size
|
||||||
}
|
}
|
||||||
res := (ptr)[:size]
|
res := (ptr)[:size]
|
||||||
sanitizer.address_unpoison(res)
|
// sanitizer.address_unpoison(res)
|
||||||
#no_bounds_check return res, nil
|
#no_bounds_check return res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
package mem_tlsf
|
package mem_tlsf
|
||||||
|
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
import "base:sanitizer"
|
// import "base:sanitizer"
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
// log2 of number of linear subdivisions of block sizes.
|
// log2 of number of linear subdivisions of block sizes.
|
||||||
@@ -210,7 +210,7 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) ->
|
|||||||
return nil, .Out_Of_Memory
|
return nil, .Out_Of_Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizer.address_poison(new_pool_buf)
|
// sanitizer.address_poison(new_pool_buf)
|
||||||
|
|
||||||
// Allocate a new link in the `control.pool` tracking structure.
|
// Allocate a new link in the `control.pool` tracking structure.
|
||||||
new_pool := new_clone(Pool{
|
new_pool := new_clone(Pool{
|
||||||
@@ -277,7 +277,7 @@ free_with_size :: proc(control: ^Allocator, ptr: rawptr, size: uint) {
|
|||||||
|
|
||||||
block := block_from_ptr(ptr)
|
block := block_from_ptr(ptr)
|
||||||
assert(!block_is_free(block), "block already marked as free") // double free
|
assert(!block_is_free(block), "block already marked as free") // double free
|
||||||
sanitizer.address_poison(ptr, block.size)
|
// sanitizer.address_poison(ptr, block.size)
|
||||||
block_mark_as_free(block)
|
block_mark_as_free(block)
|
||||||
block = block_merge_prev(control, block)
|
block = block_merge_prev(control, block)
|
||||||
block = block_merge_next(control, block)
|
block = block_merge_next(control, block)
|
||||||
@@ -321,7 +321,7 @@ resize :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, align
|
|||||||
|
|
||||||
block_trim_used(control, block, adjust)
|
block_trim_used(control, block, adjust)
|
||||||
res = ([^]byte)(ptr)[:new_size]
|
res = ([^]byte)(ptr)[:new_size]
|
||||||
sanitizer.address_unpoison(res)
|
// sanitizer.address_unpoison(res)
|
||||||
|
|
||||||
if min_size < new_size {
|
if min_size < new_size {
|
||||||
to_zero := ([^]byte)(ptr)[min_size:new_size]
|
to_zero := ([^]byte)(ptr)[min_size:new_size]
|
||||||
@@ -789,7 +789,7 @@ block_prepare_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint
|
|||||||
block_trim_free(control, block, size)
|
block_trim_free(control, block, size)
|
||||||
block_mark_as_used(block)
|
block_mark_as_used(block)
|
||||||
res = ([^]byte)(block_to_ptr(block))[:size]
|
res = ([^]byte)(block_to_ptr(block))[:size]
|
||||||
sanitizer.address_unpoison(res)
|
// sanitizer.address_unpoison(res)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-12
@@ -3,7 +3,7 @@ package mem_virtual
|
|||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
|
|
||||||
import "base:sanitizer"
|
// import "base:sanitizer"
|
||||||
|
|
||||||
Arena_Kind :: enum uint {
|
Arena_Kind :: enum uint {
|
||||||
Growing = 0, // Chained memory blocks (singly linked list).
|
Growing = 0, // Chained memory blocks (singly linked list).
|
||||||
@@ -55,7 +55,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
|
|||||||
if arena.minimum_block_size == 0 {
|
if arena.minimum_block_size == 0 {
|
||||||
arena.minimum_block_size = reserved
|
arena.minimum_block_size = reserved
|
||||||
}
|
}
|
||||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
// sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_STATIC_R
|
|||||||
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||||
arena.total_used = 0
|
arena.total_used = 0
|
||||||
arena.total_reserved = arena.curr_block.reserved
|
arena.total_reserved = arena.curr_block.reserved
|
||||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
// sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Erro
|
|||||||
|
|
||||||
arena.kind = .Buffer
|
arena.kind = .Buffer
|
||||||
|
|
||||||
sanitizer.address_poison(buffer[:])
|
// sanitizer.address_poison(buffer[:])
|
||||||
|
|
||||||
block_base := raw_data(buffer)
|
block_base := raw_data(buffer)
|
||||||
block := (^Memory_Block)(block_base)
|
block := (^Memory_Block)(block_base)
|
||||||
@@ -163,7 +163,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
|||||||
arena.total_used = arena.curr_block.used
|
arena.total_used = arena.curr_block.used
|
||||||
}
|
}
|
||||||
|
|
||||||
sanitizer.address_unpoison(data)
|
// sanitizer.address_unpoison(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
|
|||||||
mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:prev_pos-pos])
|
mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:prev_pos-pos])
|
||||||
}
|
}
|
||||||
arena.total_used = arena.curr_block.used
|
arena.total_used = arena.curr_block.used
|
||||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
// sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||||
return true
|
return true
|
||||||
} else if pos == 0 {
|
} else if pos == 0 {
|
||||||
arena.total_used = 0
|
arena.total_used = 0
|
||||||
@@ -200,7 +200,7 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
|
|||||||
arena.total_reserved -= free_block.reserved
|
arena.total_reserved -= free_block.reserved
|
||||||
|
|
||||||
arena.curr_block = free_block.prev
|
arena.curr_block = free_block.prev
|
||||||
sanitizer.address_poison(free_block.base[:free_block.committed])
|
// sanitizer.address_poison(free_block.base[:free_block.committed])
|
||||||
memory_block_dealloc(free_block)
|
memory_block_dealloc(free_block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,9 +219,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
|
|||||||
if arena.curr_block != nil {
|
if arena.curr_block != nil {
|
||||||
curr_block_used := int(arena.curr_block.used)
|
curr_block_used := int(arena.curr_block.used)
|
||||||
arena.curr_block.used = 0
|
arena.curr_block.used = 0
|
||||||
sanitizer.address_unpoison(arena.curr_block.base[:curr_block_used])
|
// sanitizer.address_unpoison(arena.curr_block.base[:curr_block_used])
|
||||||
mem.zero(arena.curr_block.base, curr_block_used)
|
mem.zero(arena.curr_block.base, curr_block_used)
|
||||||
sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
// sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed])
|
||||||
}
|
}
|
||||||
arena.total_used = 0
|
arena.total_used = 0
|
||||||
case .Static, .Buffer:
|
case .Static, .Buffer:
|
||||||
@@ -349,7 +349,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
if size < old_size {
|
if size < old_size {
|
||||||
// shrink data in-place
|
// shrink data in-place
|
||||||
data = old_data[:size]
|
data = old_data[:size]
|
||||||
sanitizer.address_poison(old_data[size:old_size])
|
// sanitizer.address_poison(old_data[size:old_size])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +363,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
_ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return
|
_ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return
|
||||||
arena.total_used += block.used - prev_used
|
arena.total_used += block.used - prev_used
|
||||||
data = block.base[start:new_end]
|
data = block.base[start:new_end]
|
||||||
sanitizer.address_unpoison(data)
|
// sanitizer.address_unpoison(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(new_memory, old_data[:old_size])
|
copy(new_memory, old_data[:old_size])
|
||||||
sanitizer.address_poison(old_data[:old_size])
|
// sanitizer.address_poison(old_data[:old_size])
|
||||||
return new_memory, nil
|
return new_memory, nil
|
||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
set := (^mem.Allocator_Mode_Set)(old_memory)
|
set := (^mem.Allocator_Mode_Set)(old_memory)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package mem_virtual
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
import "base:sanitizer"
|
// import "base:sanitizer"
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
_ :: runtime
|
_ :: runtime
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Erro
|
|||||||
|
|
||||||
@(no_sanitize_address)
|
@(no_sanitize_address)
|
||||||
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||||
sanitizer.address_unpoison(data, size)
|
// sanitizer.address_unpoison(data, size)
|
||||||
return _commit(data, size)
|
return _commit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,13 +35,13 @@ reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: All
|
|||||||
|
|
||||||
@(no_sanitize_address)
|
@(no_sanitize_address)
|
||||||
decommit :: proc "contextless" (data: rawptr, size: uint) {
|
decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
sanitizer.address_poison(data, size)
|
// sanitizer.address_poison(data, size)
|
||||||
_decommit(data, size)
|
_decommit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(no_sanitize_address)
|
@(no_sanitize_address)
|
||||||
release :: proc "contextless" (data: rawptr, size: uint) {
|
release :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
sanitizer.address_unpoison(data, size)
|
// sanitizer.address_unpoison(data, size)
|
||||||
_release(data, size)
|
_release(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint,
|
|||||||
|
|
||||||
data = block.base[block.used+alignment_offset:][:min_size]
|
data = block.base[block.used+alignment_offset:][:min_size]
|
||||||
block.used += size
|
block.used += size
|
||||||
sanitizer.address_unpoison(data)
|
// sanitizer.address_unpoison(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,3 +193,111 @@ fail_if_allocations_overlap :: proc(t: ^testing.T, a, b: []byte) {
|
|||||||
testing.fail_now(t, "Allocations overlapped")
|
testing.fail_now(t, "Allocations overlapped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This merely does a few simple operations to test basic sanity.
|
||||||
|
//
|
||||||
|
// A serious test of an allocator would require hooking it up to a benchmark or
|
||||||
|
// a large, complicated program in order to get all manner of usage patterns.
|
||||||
|
basic_sanity_test :: proc(t: ^testing.T, allocator: mem.Allocator, limit: int, loc := #caller_location) -> bool {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
|
{
|
||||||
|
a := make([dynamic]u8)
|
||||||
|
for i in 0..<limit {
|
||||||
|
append(&a, u8(i))
|
||||||
|
}
|
||||||
|
testing.expect_value(t, len(a), limit, loc) or_return
|
||||||
|
for i in 0..<limit {
|
||||||
|
testing.expect_value(t, a[i], u8(i), loc) or_return
|
||||||
|
}
|
||||||
|
delete(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
v := make([]u8, limit)
|
||||||
|
testing.expect_value(t, len(v), limit, loc) or_return
|
||||||
|
for i in 0..<limit {
|
||||||
|
v[i] = u8(i)
|
||||||
|
testing.expect_value(t, v[i], u8(i), loc) or_return
|
||||||
|
}
|
||||||
|
delete(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
for i in 0..<limit {
|
||||||
|
v := make([]u8, 1)
|
||||||
|
v[0] = u8(i)
|
||||||
|
testing.expect_value(t, v[0], u8(i), loc) or_return
|
||||||
|
delete(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_scratch :: proc(t: ^testing.T) {
|
||||||
|
N :: 4096
|
||||||
|
sa: mem.Scratch_Allocator
|
||||||
|
mem.scratch_init(&sa, N)
|
||||||
|
defer mem.scratch_destroy(&sa)
|
||||||
|
basic_sanity_test(t, mem.scratch_allocator(&sa), N / 4)
|
||||||
|
basic_sanity_test(t, mem.scratch_allocator(&sa), N / 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_stack :: proc(t: ^testing.T) {
|
||||||
|
N :: 4096
|
||||||
|
buf: [N]u8
|
||||||
|
|
||||||
|
sa: mem.Stack
|
||||||
|
mem.stack_init(&sa, buf[:])
|
||||||
|
basic_sanity_test(t, mem.stack_allocator(&sa), N / 4)
|
||||||
|
basic_sanity_test(t, mem.stack_allocator(&sa), N / 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_small_stack :: proc(t: ^testing.T) {
|
||||||
|
N :: 4096
|
||||||
|
buf: [N]u8
|
||||||
|
|
||||||
|
ss: mem.Small_Stack
|
||||||
|
mem.small_stack_init(&ss, buf[:])
|
||||||
|
basic_sanity_test(t, mem.small_stack_allocator(&ss), N / 4)
|
||||||
|
// The test cannot be run a second time on top of the last for a Small
|
||||||
|
// Stack because the dynamic array inside will resize and leave a gap, thus
|
||||||
|
// limiting the amount of space.
|
||||||
|
basic_sanity_test(t, mem.small_stack_allocator(&ss), N / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_dynamic_arena :: proc(t: ^testing.T) {
|
||||||
|
da: mem.Dynamic_Arena
|
||||||
|
mem.dynamic_arena_init(&da)
|
||||||
|
defer mem.dynamic_arena_destroy(&da)
|
||||||
|
basic_sanity_test(t, mem.dynamic_arena_allocator(&da), da.block_size / 4)
|
||||||
|
basic_sanity_test(t, mem.dynamic_arena_allocator(&da), da.block_size / 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_buddy :: proc(t: ^testing.T) {
|
||||||
|
N :: 4096
|
||||||
|
buf: [N]u8
|
||||||
|
|
||||||
|
ba: mem.Buddy_Allocator
|
||||||
|
mem.buddy_allocator_init(&ba, buf[:], align_of(u8))
|
||||||
|
basic_sanity_test(t, mem.buddy_allocator(&ba), N / 8)
|
||||||
|
basic_sanity_test(t, mem.buddy_allocator(&ba), N / 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_rollback :: proc(t: ^testing.T) {
|
||||||
|
N :: 4096
|
||||||
|
buf: [N]u8
|
||||||
|
|
||||||
|
rb: mem.Rollback_Stack
|
||||||
|
mem.rollback_stack_init(&rb, buf[:])
|
||||||
|
basic_sanity_test(t, mem.rollback_stack_allocator(&rb), N / 8)
|
||||||
|
basic_sanity_test(t, mem.rollback_stack_allocator(&rb), N / 8)
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
|
|||||||
..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b
|
||||||
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
|
||||||
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
|
||||||
|
..\..\..\odin test ..\test_issue_2694.odin %COMMON% || exit /b
|
||||||
..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
|
||||||
..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b
|
||||||
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b
|
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ $ODIN test ../test_issue_2466.odin $COMMON
|
|||||||
$ODIN test ../test_issue_2615.odin $COMMON
|
$ODIN test ../test_issue_2615.odin $COMMON
|
||||||
$ODIN test ../test_issue_2637.odin $COMMON
|
$ODIN test ../test_issue_2637.odin $COMMON
|
||||||
$ODIN test ../test_issue_2666.odin $COMMON
|
$ODIN test ../test_issue_2666.odin $COMMON
|
||||||
|
$ODIN test ../test_issue_2694.odin $COMMON
|
||||||
$ODIN test ../test_issue_4210.odin $COMMON
|
$ODIN test ../test_issue_4210.odin $COMMON
|
||||||
$ODIN test ../test_issue_4364.odin $COMMON
|
$ODIN test ../test_issue_4364.odin $COMMON
|
||||||
$ODIN test ../test_issue_4584.odin $COMMON
|
$ODIN test ../test_issue_4584.odin $COMMON
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package test_issues
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:encoding/json"
|
||||||
|
import "core:log"
|
||||||
|
import "core:mem"
|
||||||
|
import "core:testing"
|
||||||
|
|
||||||
|
// This is a minimal reproduction of the code in #2694.
|
||||||
|
// It exemplifies the original problem as briefly as possible.
|
||||||
|
|
||||||
|
SAMPLE_JSON :: `
|
||||||
|
{
|
||||||
|
"foo": 0,
|
||||||
|
"things": [
|
||||||
|
{ "a": "ZZZZ"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_issue_2694 :: proc(t: ^testing.T) {
|
||||||
|
into: struct {
|
||||||
|
foo: int,
|
||||||
|
things: []json.Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch := new(mem.Scratch_Allocator)
|
||||||
|
defer free(scratch)
|
||||||
|
if mem.scratch_allocator_init(scratch, 4 * mem.Megabyte) != .None {
|
||||||
|
log.error("unable to initialize scratch allocator")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer mem.scratch_allocator_destroy(scratch)
|
||||||
|
|
||||||
|
err := json.unmarshal_string(SAMPLE_JSON, &into, allocator = mem.scratch_allocator(scratch))
|
||||||
|
testing.expect(t, err == nil)
|
||||||
|
|
||||||
|
output := fmt.tprintf("%v", into)
|
||||||
|
expected := `{foo = 0, things = [map[a="ZZZZ"]]}`
|
||||||
|
testing.expectf(t, output == expected, "\n\texpected: %q\n\tgot: %q", expected, output)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user