compiler/
lib/
examples/
std/
arch/
char/
collections/
graph/
lang/
alloc/
tests.rad
7.5 KiB
ast/
gen/
il/
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.9 KiB
gen.rad
513 B
il.rad
20.4 KiB
lower.rad
321.7 KiB
module.rad
17.3 KiB
package.rad
1.3 KiB
parser.rad
92.2 KiB
resolver.rad
511.1 KiB
scanner.rad
17.9 KiB
sexpr.rad
6.7 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
graph.rad
4.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
299 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CELL_PERMISSIONS
6.8 KiB
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
5.4 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
808 B
lib/std/lang/alloc/tests.rad
raw
| 1 | //! Tests for the bump allocator. |
| 2 | |
| 3 | use std::testing; |
| 4 | |
| 5 | /// Test basic allocation. |
| 6 | @test unsafe fn testAllocBasic() throws (testing::TestError) { |
| 7 | static STORAGE: [u8; 64] = [0; 64]; |
| 8 | let mut arena = super::new(&mut STORAGE[..]); |
| 9 | |
| 10 | let ptr = try! super::alloc(&mut arena, 4, 4); |
| 11 | try testing::expect(super::used(&arena) == 4); |
| 12 | try testing::expect(super::remaining(&arena) == 60); |
| 13 | } |
| 14 | |
| 15 | /// Test that allocations are properly aligned. |
| 16 | @test unsafe fn testAllocAlignment() throws (testing::TestError) { |
| 17 | static STORAGE: [u8; 64] = [0; 64]; |
| 18 | let mut arena = super::new(&mut STORAGE[..]); |
| 19 | |
| 20 | // Allocate 1 byte with 1-byte alignment. |
| 21 | let p1 = try! super::alloc(&mut arena, 1, 1); |
| 22 | try testing::expect(super::used(&arena) == 1); |
| 23 | |
| 24 | // Allocate 4 bytes with 4-byte alignment - should pad to offset 4. |
| 25 | let p2 = try! super::alloc(&mut arena, 4, 4); |
| 26 | try testing::expect(super::used(&arena) == 8); // 1 + 3 padding + 4 |
| 27 | } |
| 28 | |
| 29 | /// Test multiple allocations. |
| 30 | @test unsafe fn testAllocMultiple() throws (testing::TestError) { |
| 31 | static STORAGE: [u8; 128] = [0; 128]; |
| 32 | let mut arena = super::new(&mut STORAGE[..]); |
| 33 | |
| 34 | let p1 = try! super::alloc(&mut arena, 8, 4); |
| 35 | let p2 = try! super::alloc(&mut arena, 16, 4); |
| 36 | let p3 = try! super::alloc(&mut arena, 4, 4); |
| 37 | |
| 38 | try testing::expect(super::used(&arena) == 28); // 8 + 16 + 4 |
| 39 | } |
| 40 | |
| 41 | /// Test that arena throws when exhausted. |
| 42 | @test unsafe fn testAllocExhausted() throws (testing::TestError) { |
| 43 | static STORAGE: [u8; 16] = [0; 16]; |
| 44 | let mut arena = super::new(&mut STORAGE[..]); |
| 45 | |
| 46 | // This should succeed. |
| 47 | let p1 = try! super::alloc(&mut arena, 8, 4); |
| 48 | |
| 49 | // This should also succeed. |
| 50 | let p2 = try! super::alloc(&mut arena, 8, 4); |
| 51 | |
| 52 | // Arena is now full, this should fail. |
| 53 | let mut failed = false; |
| 54 | try super::alloc(&mut arena, 1, 1) catch { |
| 55 | set failed = true; |
| 56 | }; |
| 57 | try testing::expect(failed); |
| 58 | } |
| 59 | |
| 60 | /// Test that reset allows reuse of memory. |
| 61 | @test unsafe fn testAllocReset() throws (testing::TestError) { |
| 62 | static STORAGE: [u8; 32] = [0; 32]; |
| 63 | let mut arena = super::new(&mut STORAGE[..]); |
| 64 | |
| 65 | let p1 = try! super::alloc(&mut arena, 16, 4); |
| 66 | try testing::expect(super::used(&arena) == 16); |
| 67 | |
| 68 | super::reset(&mut arena); |
| 69 | try testing::expect(super::used(&arena) == 0); |
| 70 | try testing::expect(super::remaining(&arena) == 32); |
| 71 | |
| 72 | // Should be able to allocate again. |
| 73 | let p2 = try! super::alloc(&mut arena, 32, 4); |
| 74 | } |
| 75 | |
| 76 | /// Test alignment when offset is already aligned. |
| 77 | @test unsafe fn testAllocAlreadyAligned() throws (testing::TestError) { |
| 78 | static STORAGE: [u8; 64] = [0; 64]; |
| 79 | let mut arena = super::new(&mut STORAGE[..]); |
| 80 | |
| 81 | // Allocate 4 bytes - offset becomes 4, already aligned for next 4-byte alloc. |
| 82 | let p1 = try! super::alloc(&mut arena, 4, 4); |
| 83 | try testing::expect(super::used(&arena) == 4); |
| 84 | |
| 85 | // Next 4-byte aligned allocation should not add padding. |
| 86 | let p2 = try! super::alloc(&mut arena, 4, 4); |
| 87 | try testing::expect(super::used(&arena) == 8); |
| 88 | } |
| 89 | |
| 90 | /// Test allocation that would overflow with alignment padding. |
| 91 | @test unsafe fn testAllocOverflowWithPadding() throws (testing::TestError) { |
| 92 | static STORAGE: [u8; 16] = [0; 16]; |
| 93 | let mut arena = super::new(&mut STORAGE[..]); |
| 94 | |
| 95 | // Allocate 1 byte, offset is now 1. |
| 96 | let p1 = try! super::alloc(&mut arena, 1, 1); |
| 97 | |
| 98 | // Try to allocate 16 bytes with 4-byte alignment. |
| 99 | // Aligned offset would be 4, then 4 + 16 = 20 > 16, so should fail. |
| 100 | let mut failed = false; |
| 101 | try super::alloc(&mut arena, 16, 4) catch { |
| 102 | set failed = true; |
| 103 | }; |
| 104 | try testing::expect(failed); |
| 105 | } |
| 106 | |
| 107 | /// Test the Allocator interface backed by an arena. |
| 108 | @test unsafe fn testAllocator() throws (testing::TestError) { |
| 109 | static STORAGE: [u8; 256] = [0; 256]; |
| 110 | let mut arena = super::new(&mut STORAGE[..]); |
| 111 | let a = super::arenaAllocator(&mut arena); |
| 112 | |
| 113 | // Allocate through the Allocator indirection. |
| 114 | let p1 = a.func(a.ctx, 16, 4); |
| 115 | try testing::expect((p1 as u64 & 3) == 0); |
| 116 | |
| 117 | let p2 = a.func(a.ctx, 8, 8); |
| 118 | try testing::expect((p2 as u64 & 7) == 0); |
| 119 | try testing::expect(super::used(&arena) as u64 == p2 as u64 - &STORAGE[0] as u64 + 8); |
| 120 | |
| 121 | // Verify the pointers are distinct. |
| 122 | try testing::expect(p1 as u64 <> p2 as u64); |
| 123 | } |
| 124 | |
| 125 | /// Large counts and offsets must fail before arithmetic wraps or storage changes. |
| 126 | @test unsafe fn testAllocOverflow() throws (testing::TestError) { |
| 127 | static bytes: [u8; 64] = [0; 64]; |
| 128 | let mut arena = super::new(&mut bytes[..]); |
| 129 | set arena.offset = 8; |
| 130 | let mut failed: u32 = 0; |
| 131 | try super::allocSlice(&mut arena, 8, 8, 0x20000000) catch { |
| 132 | set failed += 1; |
| 133 | }; |
| 134 | try super::alloc(&mut arena, 0xffffffff, 8) catch { |
| 135 | set failed += 1; |
| 136 | }; |
| 137 | try testing::expect(failed == 2 and arena.offset == 8); |
| 138 | set arena.offset = 0xfffffff8; |
| 139 | try super::alloc(&mut arena, 16, 16) catch { |
| 140 | set failed += 1; |
| 141 | }; |
| 142 | try testing::expect(failed == 3 and arena.offset == 0xfffffff8); |
| 143 | set arena.offset = 8; |
| 144 | let storage = try super::alloc(&mut arena, 8, 8) catch { |
| 145 | throw testing::TestError::Failed; |
| 146 | }; |
| 147 | try testing::expect((storage as u64 & 7) == 0); |
| 148 | try testing::expect(arena.offset as u64 == storage as u64 - &bytes[0] as u64 + 8); |
| 149 | } |
| 150 | |
| 151 | /// Allocation alignment uses the backing address and preserves distinct objects. |
| 152 | @test unsafe fn testAllocUnalignedBacking() throws (testing::TestError) { |
| 153 | static STORAGE: [u8; 96] = [0; 96]; |
| 154 | for start in 0..16 { |
| 155 | let mut arena = super::new(&mut STORAGE[start..]); |
| 156 | let first = try! super::allocRaw(&mut arena, 8, 16) as *unsafe mut u64; |
| 157 | set *first = 123; |
| 158 | let second = try! super::allocRaw(&mut arena, 8, 16) as *unsafe mut u64; |
| 159 | set *second = 456; |
| 160 | try testing::expect((first as u64 & 15) == 0); |
| 161 | try testing::expect((second as u64 & 15) == 0); |
| 162 | try testing::expect(second as u64 >= first as u64 + 8); |
| 163 | try testing::expect(*first == 123); |
| 164 | try testing::expect(*second == 456); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | /// Capacity failure and arithmetic overflow leave the arena and live data intact. |
| 169 | @test unsafe fn testAllocFailureAtomicity() throws (testing::TestError) { |
| 170 | static STORAGE: [u8; 64] = [0; 64]; |
| 171 | let mut arena = super::new(&mut STORAGE[..]); |
| 172 | let first = try! super::allocRaw(&mut arena, 1, 1) as *unsafe mut u8; |
| 173 | set *first = 42; |
| 174 | for size in [64 as u32, 4294967295 as u32] { |
| 175 | let saved = super::used(&arena); |
| 176 | let mut failed = false; |
| 177 | try super::alloc(&mut arena, size, 1) catch { |
| 178 | set failed = true; |
| 179 | }; |
| 180 | try testing::expect(failed); |
| 181 | try testing::expect(super::used(&arena) == saved); |
| 182 | try testing::expect(*first == 42); |
| 183 | } |
| 184 | let next = try! super::allocRaw(&mut arena, 1, 1) as *unsafe mut u8; |
| 185 | try testing::expect(next as u64 == first as u64 + 1); |
| 186 | } |
| 187 | |
| 188 | /// Slice count multiplication fails before either allocation API changes state. |
| 189 | @test unsafe fn testAllocSliceOverflowAtomicity() throws (testing::TestError) { |
| 190 | static STORAGE: [u8; 64] = [0; 64]; |
| 191 | let mut arena = super::new(&mut STORAGE[..]); |
| 192 | let first = try! super::allocRaw(&mut arena, 1, 1) as *unsafe mut u8; |
| 193 | set *first = 42; |
| 194 | let saved = super::used(&arena); |
| 195 | let mut failed = false; |
| 196 | try super::allocSlice(&mut arena, 4, 4, 1073741825) catch { |
| 197 | set failed = true; |
| 198 | }; |
| 199 | try testing::expect(failed); |
| 200 | try testing::expect(super::used(&arena) == saved); |
| 201 | set failed = false; |
| 202 | try super::allocRawSlice(&mut arena, 4, 4, 1073741825) catch { |
| 203 | set failed = true; |
| 204 | }; |
| 205 | try testing::expect(failed); |
| 206 | try testing::expect(super::used(&arena) == saved); |
| 207 | try testing::expect(*first == 42); |
| 208 | } |