lib/std/lang/alloc/tests.rad 7.5 KiB 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
}