1 //===-- Unittests for a block of memory -------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "src/__support/CPP/array.h"
11 #include "src/__support/CPP/bit.h"
12 #include "src/__support/CPP/span.h"
13 #include "src/__support/block.h"
14 #include "src/string/memcpy.h"
15 #include "test/UnitTest/Test.h"
17 using LIBC_NAMESPACE::Block
;
18 using LIBC_NAMESPACE::cpp::array
;
19 using LIBC_NAMESPACE::cpp::bit_ceil
;
20 using LIBC_NAMESPACE::cpp::byte
;
21 using LIBC_NAMESPACE::cpp::span
;
23 TEST(LlvmLibcBlockTest
, CanCreateSingleAlignedBlock
) {
24 constexpr size_t kN
= 1024;
25 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
27 auto result
= Block::init(bytes
);
28 ASSERT_TRUE(result
.has_value());
29 Block
*block
= *result
;
31 Block
*last
= block
->next();
32 ASSERT_NE(last
, static_cast<Block
*>(nullptr));
33 constexpr size_t last_outer_size
= Block::BLOCK_OVERHEAD
;
34 EXPECT_EQ(last
->outer_size(), last_outer_size
);
35 EXPECT_EQ(last
->prev_free(), block
);
36 EXPECT_TRUE(last
->used());
38 EXPECT_EQ(block
->outer_size(), kN
- last_outer_size
);
39 constexpr size_t last_prev_field_size
= sizeof(size_t);
40 EXPECT_EQ(block
->inner_size(), kN
- last_outer_size
- Block::BLOCK_OVERHEAD
+
41 last_prev_field_size
);
42 EXPECT_EQ(block
->prev_free(), static_cast<Block
*>(nullptr));
43 EXPECT_FALSE(block
->used());
46 TEST(LlvmLibcBlockTest
, CanCreateUnalignedSingleBlock
) {
47 constexpr size_t kN
= 1024;
49 // Force alignment, so we can un-force it below
50 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
51 span
<byte
> aligned(bytes
);
53 auto result
= Block::init(aligned
.subspan(1));
54 EXPECT_TRUE(result
.has_value());
57 TEST(LlvmLibcBlockTest
, CannotCreateTooSmallBlock
) {
59 auto result
= Block::init(bytes
);
60 EXPECT_FALSE(result
.has_value());
63 TEST(LlvmLibcBlockTest
, CanSplitBlock
) {
64 constexpr size_t kN
= 1024;
65 constexpr size_t prev_field_size
= sizeof(size_t);
66 // Give the split position a large alignment.
67 constexpr size_t kSplitN
= 512 + prev_field_size
;
69 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
70 auto result
= Block::init(bytes
);
71 ASSERT_TRUE(result
.has_value());
72 auto *block1
= *result
;
73 size_t orig_size
= block1
->outer_size();
75 result
= block1
->split(kSplitN
);
76 ASSERT_TRUE(result
.has_value());
77 auto *block2
= *result
;
79 EXPECT_EQ(block1
->inner_size(), kSplitN
);
80 EXPECT_EQ(block1
->outer_size(),
81 kSplitN
- prev_field_size
+ Block::BLOCK_OVERHEAD
);
83 EXPECT_EQ(block2
->outer_size(), orig_size
- block1
->outer_size());
84 EXPECT_FALSE(block2
->used());
86 EXPECT_EQ(block1
->next(), block2
);
87 EXPECT_EQ(block2
->prev_free(), block1
);
90 TEST(LlvmLibcBlockTest
, CanSplitBlockUnaligned
) {
91 constexpr size_t kN
= 1024;
93 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
94 auto result
= Block::init(bytes
);
95 ASSERT_TRUE(result
.has_value());
96 Block
*block1
= *result
;
97 size_t orig_size
= block1
->outer_size();
99 constexpr size_t kSplitN
= 513;
100 constexpr size_t prev_field_size
= sizeof(size_t);
101 uintptr_t split_addr
=
102 reinterpret_cast<uintptr_t>(block1
) + (kSplitN
- prev_field_size
);
103 // Round split_addr up to a multiple of the alignment.
104 split_addr
+= alignof(Block
) - (split_addr
% alignof(Block
));
105 uintptr_t split_len
= split_addr
- (uintptr_t)&bytes
+ prev_field_size
;
107 result
= block1
->split(kSplitN
);
108 ASSERT_TRUE(result
.has_value());
109 Block
*block2
= *result
;
111 EXPECT_EQ(block1
->inner_size(), split_len
);
113 EXPECT_EQ(block2
->outer_size(), orig_size
- block1
->outer_size());
114 EXPECT_FALSE(block2
->used());
116 EXPECT_EQ(block1
->next(), block2
);
117 EXPECT_EQ(block2
->prev_free(), block1
);
120 TEST(LlvmLibcBlockTest
, CanSplitMidBlock
) {
121 // split once, then split the original block again to ensure that the
122 // pointers get rewired properly.
126 // [[ BLOCK1 ]][[ BLOCK2 ]]
128 // [[ BLOCK1 ]][[ BLOCK3 ]][[ BLOCK2 ]]
130 constexpr size_t kN
= 1024;
131 constexpr size_t kSplit1
= 512;
132 constexpr size_t kSplit2
= 256;
134 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
135 auto result
= Block::init(bytes
);
136 ASSERT_TRUE(result
.has_value());
137 Block
*block1
= *result
;
139 result
= block1
->split(kSplit1
);
140 ASSERT_TRUE(result
.has_value());
141 Block
*block2
= *result
;
143 result
= block1
->split(kSplit2
);
144 ASSERT_TRUE(result
.has_value());
145 Block
*block3
= *result
;
147 EXPECT_EQ(block1
->next(), block3
);
148 EXPECT_EQ(block3
->prev_free(), block1
);
149 EXPECT_EQ(block3
->next(), block2
);
150 EXPECT_EQ(block2
->prev_free(), block3
);
153 TEST(LlvmLibcBlockTest
, CannotSplitTooSmallBlock
) {
154 constexpr size_t kN
= 64;
155 constexpr size_t kSplitN
= kN
+ 1;
157 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
158 auto result
= Block::init(bytes
);
159 ASSERT_TRUE(result
.has_value());
160 Block
*block
= *result
;
162 result
= block
->split(kSplitN
);
163 ASSERT_FALSE(result
.has_value());
166 TEST(LlvmLibcBlockTest
, CannotSplitBlockWithoutHeaderSpace
) {
167 constexpr size_t kN
= 1024;
168 constexpr size_t kSplitN
= kN
- 2 * Block::BLOCK_OVERHEAD
- 1;
170 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
171 auto result
= Block::init(bytes
);
172 ASSERT_TRUE(result
.has_value());
173 Block
*block
= *result
;
175 result
= block
->split(kSplitN
);
176 ASSERT_FALSE(result
.has_value());
179 TEST(LlvmLibcBlockTest
, CannotMakeBlockLargerInSplit
) {
180 // Ensure that we can't ask for more space than the block actually has...
181 constexpr size_t kN
= 1024;
183 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
184 auto result
= Block::init(bytes
);
185 ASSERT_TRUE(result
.has_value());
186 Block
*block
= *result
;
188 result
= block
->split(block
->inner_size() + 1);
189 ASSERT_FALSE(result
.has_value());
192 TEST(LlvmLibcBlockTest
, CannotMakeSecondBlockLargerInSplit
) {
193 // Ensure that the second block in split is at least of the size of header.
194 constexpr size_t kN
= 1024;
196 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
197 auto result
= Block::init(bytes
);
198 ASSERT_TRUE(result
.has_value());
199 Block
*block
= *result
;
201 result
= block
->split(block
->inner_size() - Block::BLOCK_OVERHEAD
+ 1);
202 ASSERT_FALSE(result
.has_value());
205 TEST(LlvmLibcBlockTest
, CanMakeMinimalSizeFirstBlock
) {
206 // This block does support splitting with minimal payload size.
207 constexpr size_t kN
= 1024;
208 constexpr size_t minimal_size
= sizeof(size_t);
210 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
211 auto result
= Block::init(bytes
);
212 ASSERT_TRUE(result
.has_value());
213 Block
*block
= *result
;
215 result
= block
->split(minimal_size
);
216 ASSERT_TRUE(result
.has_value());
217 EXPECT_EQ(block
->inner_size(), minimal_size
);
220 TEST(LlvmLibcBlockTest
, CanMakeMinimalSizeSecondBlock
) {
221 // Likewise, the split block can be minimal-width.
222 constexpr size_t kN
= 1024;
223 constexpr size_t minimal_size
= sizeof(size_t);
225 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
226 auto result
= Block::init(bytes
);
227 ASSERT_TRUE(result
.has_value());
228 Block
*block1
= *result
;
230 result
= block1
->split(block1
->inner_size() - Block::BLOCK_OVERHEAD
);
231 ASSERT_TRUE(result
.has_value());
232 Block
*block2
= *result
;
234 EXPECT_EQ(block2
->inner_size(), minimal_size
);
237 TEST(LlvmLibcBlockTest
, CanMarkBlockUsed
) {
238 constexpr size_t kN
= 1024;
240 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
241 auto result
= Block::init(bytes
);
242 ASSERT_TRUE(result
.has_value());
243 Block
*block
= *result
;
244 size_t orig_size
= block
->outer_size();
247 EXPECT_TRUE(block
->used());
248 EXPECT_EQ(block
->outer_size(), orig_size
);
251 EXPECT_FALSE(block
->used());
254 TEST(LlvmLibcBlockTest
, CannotSplitUsedBlock
) {
255 constexpr size_t kN
= 1024;
256 constexpr size_t kSplitN
= 512;
258 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
259 auto result
= Block::init(bytes
);
260 ASSERT_TRUE(result
.has_value());
261 Block
*block
= *result
;
264 result
= block
->split(kSplitN
);
265 ASSERT_FALSE(result
.has_value());
268 TEST(LlvmLibcBlockTest
, CanMergeWithNextBlock
) {
269 // Do the three way merge from "CanSplitMidBlock", and let's
270 // merge block 3 and 2
271 constexpr size_t kN
= 1024;
272 // Give the split positions large alignments.
273 constexpr size_t prev_field_size
= sizeof(size_t);
274 constexpr size_t kSplit1
= 512 + prev_field_size
;
275 constexpr size_t kSplit2
= 256 + prev_field_size
;
277 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
278 auto result
= Block::init(bytes
);
279 ASSERT_TRUE(result
.has_value());
280 Block
*block1
= *result
;
281 size_t orig_size
= block1
->outer_size();
283 result
= block1
->split(kSplit1
);
284 ASSERT_TRUE(result
.has_value());
286 result
= block1
->split(kSplit2
);
287 ASSERT_TRUE(result
.has_value());
288 Block
*block3
= *result
;
290 EXPECT_TRUE(block3
->merge_next());
292 EXPECT_EQ(block1
->next(), block3
);
293 EXPECT_EQ(block3
->prev_free(), block1
);
294 EXPECT_EQ(block1
->inner_size(), kSplit2
);
295 EXPECT_EQ(block3
->outer_size(), orig_size
- block1
->outer_size());
298 TEST(LlvmLibcBlockTest
, CannotMergeWithFirstOrLastBlock
) {
299 constexpr size_t kN
= 1024;
300 constexpr size_t kSplitN
= 512;
302 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
303 auto result
= Block::init(bytes
);
304 ASSERT_TRUE(result
.has_value());
305 Block
*block1
= *result
;
307 // Do a split, just to check that the checks on next/prev are different...
308 result
= block1
->split(kSplitN
);
309 ASSERT_TRUE(result
.has_value());
310 Block
*block2
= *result
;
312 EXPECT_FALSE(block2
->merge_next());
315 TEST(LlvmLibcBlockTest
, CannotMergeUsedBlock
) {
316 constexpr size_t kN
= 1024;
317 constexpr size_t kSplitN
= 512;
319 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
;
320 auto result
= Block::init(bytes
);
321 ASSERT_TRUE(result
.has_value());
322 Block
*block
= *result
;
324 // Do a split, just to check that the checks on next/prev are different...
325 result
= block
->split(kSplitN
);
326 ASSERT_TRUE(result
.has_value());
329 EXPECT_FALSE(block
->merge_next());
332 TEST(LlvmLibcBlockTest
, CanGetBlockFromUsableSpace
) {
333 constexpr size_t kN
= 1024;
335 array
<byte
, kN
> bytes
{};
336 auto result
= Block::init(bytes
);
337 ASSERT_TRUE(result
.has_value());
338 Block
*block1
= *result
;
340 void *ptr
= block1
->usable_space();
341 Block
*block2
= Block::from_usable_space(ptr
);
342 EXPECT_EQ(block1
, block2
);
345 TEST(LlvmLibcBlockTest
, CanGetConstBlockFromUsableSpace
) {
346 constexpr size_t kN
= 1024;
348 array
<byte
, kN
> bytes
{};
349 auto result
= Block::init(bytes
);
350 ASSERT_TRUE(result
.has_value());
351 const Block
*block1
= *result
;
353 const void *ptr
= block1
->usable_space();
354 const Block
*block2
= Block::from_usable_space(ptr
);
355 EXPECT_EQ(block1
, block2
);
358 TEST(LlvmLibcBlockTest
, CanAllocate
) {
359 constexpr size_t kN
= 1024 + Block::BLOCK_OVERHEAD
;
361 // Ensure we can allocate everything up to the block size within this block.
362 for (size_t i
= 0; i
< kN
- 2 * Block::BLOCK_OVERHEAD
; ++i
) {
363 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
{};
364 auto result
= Block::init(bytes
);
365 ASSERT_TRUE(result
.has_value());
366 Block
*block
= *result
;
368 constexpr size_t ALIGN
= 1; // Effectively ignores alignment.
369 EXPECT_TRUE(block
->can_allocate(ALIGN
, i
));
371 // For each can_allocate, we should be able to do a successful call to
373 auto info
= Block::allocate(block
, ALIGN
, i
);
374 EXPECT_NE(info
.block
, static_cast<Block
*>(nullptr));
377 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
{};
378 auto result
= Block::init(bytes
);
379 ASSERT_TRUE(result
.has_value());
380 Block
*block
= *result
;
382 // Given a block of size N (assuming it's also a power of two), we should be
383 // able to allocate a block within it that's aligned to N/2. This is
384 // because regardless of where the buffer is located, we can always find a
385 // starting location within it that meets this alignment.
386 EXPECT_TRUE(block
->can_allocate(block
->outer_size() / 2, 1));
387 auto info
= Block::allocate(block
, block
->outer_size() / 2, 1);
388 EXPECT_NE(info
.block
, static_cast<Block
*>(nullptr));
391 TEST(LlvmLibcBlockTest
, AllocateAlreadyAligned
) {
392 constexpr size_t kN
= 1024;
394 alignas(Block::ALIGNMENT
) array
<byte
, kN
> bytes
{};
395 auto result
= Block::init(bytes
);
396 ASSERT_TRUE(result
.has_value());
397 Block
*block
= *result
;
399 // This should result in no new blocks.
400 constexpr size_t kAlignment
= Block::ALIGNMENT
;
401 constexpr size_t prev_field_size
= sizeof(size_t);
402 constexpr size_t kExpectedSize
= Block::ALIGNMENT
+ prev_field_size
;
403 EXPECT_TRUE(block
->can_allocate(kAlignment
, kExpectedSize
));
405 auto [aligned_block
, prev
, next
] =
406 Block::allocate(block
, Block::ALIGNMENT
, kExpectedSize
);
408 // Since this is already aligned, there should be no previous block.
409 EXPECT_EQ(prev
, static_cast<Block
*>(nullptr));
411 // Ensure we the block is aligned and the size we expect.
412 EXPECT_NE(aligned_block
, static_cast<Block
*>(nullptr));
413 EXPECT_TRUE(aligned_block
->is_usable_space_aligned(Block::ALIGNMENT
));
414 EXPECT_EQ(aligned_block
->inner_size(), kExpectedSize
);
416 // Check the next block.
417 EXPECT_NE(next
, static_cast<Block
*>(nullptr));
418 EXPECT_EQ(aligned_block
->next(), next
);
419 EXPECT_EQ(reinterpret_cast<byte
*>(next
) + next
->outer_size(),
420 bytes
.data() + bytes
.size() - Block::BLOCK_OVERHEAD
);
423 TEST(LlvmLibcBlockTest
, AllocateNeedsAlignment
) {
424 constexpr size_t kN
= 1024;
426 alignas(kN
) array
<byte
, kN
> bytes
{};
427 auto result
= Block::init(bytes
);
428 ASSERT_TRUE(result
.has_value());
429 Block
*block
= *result
;
431 // Ensure first the usable_data is only aligned to the block alignment.
432 ASSERT_EQ(block
->usable_space(), bytes
.data() + Block::BLOCK_OVERHEAD
);
433 ASSERT_EQ(block
->prev_free(), static_cast<Block
*>(nullptr));
435 // Now pick an alignment such that the usable space is not already aligned to
436 // it. We want to explicitly test that the block will split into one before
438 constexpr size_t kAlignment
= bit_ceil(Block::BLOCK_OVERHEAD
) * 8;
439 ASSERT_FALSE(block
->is_usable_space_aligned(kAlignment
));
441 constexpr size_t kSize
= 10;
442 EXPECT_TRUE(block
->can_allocate(kAlignment
, kSize
));
444 auto [aligned_block
, prev
, next
] = Block::allocate(block
, kAlignment
, kSize
);
446 // Check the previous block was created appropriately. Since this block is the
447 // first block, a new one should be made before this.
448 EXPECT_NE(prev
, static_cast<Block
*>(nullptr));
449 EXPECT_EQ(aligned_block
->prev_free(), prev
);
450 EXPECT_EQ(prev
->next(), aligned_block
);
451 EXPECT_EQ(prev
->outer_size(), reinterpret_cast<uintptr_t>(aligned_block
) -
452 reinterpret_cast<uintptr_t>(prev
));
454 // Ensure we the block is aligned and the size we expect.
455 EXPECT_NE(next
, static_cast<Block
*>(nullptr));
456 EXPECT_TRUE(aligned_block
->is_usable_space_aligned(kAlignment
));
458 // Check the next block.
459 EXPECT_NE(next
, static_cast<Block
*>(nullptr));
460 EXPECT_EQ(aligned_block
->next(), next
);
461 EXPECT_EQ(reinterpret_cast<byte
*>(next
) + next
->outer_size(),
462 bytes
.data() + bytes
.size() - Block::BLOCK_OVERHEAD
);
465 TEST(LlvmLibcBlockTest
, PreviousBlockMergedIfNotFirst
) {
466 constexpr size_t kN
= 1024;
468 alignas(kN
) array
<byte
, kN
> bytes
{};
469 auto result
= Block::init(bytes
);
470 ASSERT_TRUE(result
.has_value());
471 Block
*block
= *result
;
473 // Split the block roughly halfway and work on the second half.
474 auto result2
= block
->split(kN
/ 2);
475 ASSERT_TRUE(result2
.has_value());
476 Block
*newblock
= *result2
;
477 ASSERT_EQ(newblock
->prev_free(), block
);
478 size_t old_prev_size
= block
->outer_size();
480 // Now pick an alignment such that the usable space is not already aligned to
481 // it. We want to explicitly test that the block will split into one before
483 constexpr size_t kAlignment
= bit_ceil(Block::BLOCK_OVERHEAD
) * 8;
484 ASSERT_FALSE(newblock
->is_usable_space_aligned(kAlignment
));
486 // Ensure we can allocate in the new block.
487 constexpr size_t kSize
= Block::ALIGNMENT
;
488 EXPECT_TRUE(newblock
->can_allocate(kAlignment
, kSize
));
490 auto [aligned_block
, prev
, next
] =
491 Block::allocate(newblock
, kAlignment
, kSize
);
493 // Now there should be no new previous block. Instead, the padding we did
494 // create should be merged into the original previous block.
495 EXPECT_EQ(prev
, static_cast<Block
*>(nullptr));
496 EXPECT_EQ(aligned_block
->prev_free(), block
);
497 EXPECT_EQ(block
->next(), aligned_block
);
498 EXPECT_GT(block
->outer_size(), old_prev_size
);
501 TEST(LlvmLibcBlockTest
, CanRemergeBlockAllocations
) {
502 // Finally to ensure we made the split blocks correctly via allocate. We
503 // should be able to reconstruct the original block from the blocklets.
505 // This is the same setup as with the `AllocateNeedsAlignment` test case.
506 constexpr size_t kN
= 1024;
508 alignas(kN
) array
<byte
, kN
> bytes
{};
509 auto result
= Block::init(bytes
);
510 ASSERT_TRUE(result
.has_value());
511 Block
*block
= *result
;
512 Block
*last
= block
->next();
514 // Ensure first the usable_data is only aligned to the block alignment.
515 ASSERT_EQ(block
->usable_space(), bytes
.data() + Block::BLOCK_OVERHEAD
);
516 ASSERT_EQ(block
->prev_free(), static_cast<Block
*>(nullptr));
518 // Now pick an alignment such that the usable space is not already aligned to
519 // it. We want to explicitly test that the block will split into one before
521 constexpr size_t kAlignment
= bit_ceil(Block::BLOCK_OVERHEAD
) * 8;
522 ASSERT_FALSE(block
->is_usable_space_aligned(kAlignment
));
524 constexpr size_t kSize
= Block::ALIGNMENT
;
525 EXPECT_TRUE(block
->can_allocate(kAlignment
, kSize
));
527 auto [aligned_block
, prev
, next
] = Block::allocate(block
, kAlignment
, kSize
);
529 // Check we have the appropriate blocks.
530 ASSERT_NE(prev
, static_cast<Block
*>(nullptr));
531 ASSERT_EQ(aligned_block
->prev_free(), prev
);
532 EXPECT_NE(next
, static_cast<Block
*>(nullptr));
533 EXPECT_EQ(aligned_block
->next(), next
);
534 EXPECT_EQ(next
->next(), last
);
536 // Now check for successful merges.
537 EXPECT_TRUE(prev
->merge_next());
538 EXPECT_EQ(prev
->next(), next
);
539 EXPECT_TRUE(prev
->merge_next());
540 EXPECT_EQ(prev
->next(), last
);
542 // We should have the original buffer.
543 EXPECT_EQ(reinterpret_cast<byte
*>(prev
), &*bytes
.begin());
544 EXPECT_EQ(prev
->outer_size(), bytes
.size() - Block::BLOCK_OVERHEAD
);
545 EXPECT_EQ(reinterpret_cast<byte
*>(prev
) + prev
->outer_size(),
546 &*bytes
.end() - Block::BLOCK_OVERHEAD
);