[libc-commits] [libc] [libc] Implement dual freestore rotation for baremetal heap (PR #209811)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 14 13:50:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Schrodinger ZHU Yifan (SchrodingerZhu)
<details>
<summary>Changes</summary>
Implement dual FreeStore rotation in FreeListHeap under LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION option for baremetal targets.
- Allocations pull from active store; free() quarantines blocks into non-active store (1 - active).
- On allocation failure in active store, rotate() flips active index and migrates/coalesces quarantined blocks into the new active store.
- Added 2-bit prev_free tracking in BlockRef metadata to distinguish freestore indices.
- Added unit smoke tests and updated fuzzer for dual freestore rotation.
---
Patch is 20.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209811.diff
11 Files Affected:
- (modified) libc/cmake/modules/LLVMLibCCompileOptionRules.cmake (+4)
- (modified) libc/config/baremetal/config.json (+5)
- (modified) libc/config/config.json (+6)
- (modified) libc/fuzzing/__support/CMakeLists.txt (+2)
- (modified) libc/src/__support/block.h (+66)
- (modified) libc/src/__support/freelist_heap.h (+91-5)
- (modified) libc/src/__support/freestore.h (+34-4)
- (modified) libc/src/__support/freetrie.cpp (+8)
- (modified) libc/src/__support/freetrie.h (+4)
- (modified) libc/test/src/__support/block_test.cpp (+11-1)
- (modified) libc/test/src/__support/freelist_heap_test.cpp (+36-3)
``````````diff
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index 99defb24d249a..79f2d80bcba7a 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -189,6 +189,10 @@ function(_get_compile_options_from_config output_var)
libc_add_definition(config_options "LIBC_COPT_PRINTF_DISABLE_BITINT")
endif()
+ if(LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION)
+ libc_add_definition(config_options "LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION")
+ endif()
+
if(LIBC_COPT_USE_C_ASSERT)
list(APPEND config_options "-DLIBC_COPT_USE_C_ASSERT")
endif()
diff --git a/libc/config/baremetal/config.json b/libc/config/baremetal/config.json
index 1c52cd0093e1c..e83ed967771f1 100644
--- a/libc/config/baremetal/config.json
+++ b/libc/config/baremetal/config.json
@@ -75,5 +75,10 @@
"LIBC_CONF_CTYPE_SMALLER_ASCII": {
"value": true
}
+ },
+ "baremetal": {
+ "LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION": {
+ "value": true
+ }
}
}
diff --git a/libc/config/config.json b/libc/config/config.json
index fd7784d3d3e55..f13b5fc9c1ca7 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -189,6 +189,12 @@
"doc": "Trap with SIGFPE when feraiseexcept is called with unmasked floating point exceptions, similar to glibc's behavior. This is currently working only on x86 with SSE."
}
},
+ "baremetal": {
+ "LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION": {
+ "value": true,
+ "doc": "Enable rotational dual freestore in FreeListHeap to delay reuse of freed memory. This, when combined with sanitizers, helps detect Use-After-Free (UAF) bugs more reliably by preventing rapid reallocation of recently freed blocks."
+ }
+ },
"assert": {
"LIBC_COPT_USE_C_ASSERT": {
"value": false,
diff --git a/libc/fuzzing/__support/CMakeLists.txt b/libc/fuzzing/__support/CMakeLists.txt
index be72259036458..99de5cb97dcc5 100644
--- a/libc/fuzzing/__support/CMakeLists.txt
+++ b/libc/fuzzing/__support/CMakeLists.txt
@@ -41,6 +41,8 @@ if(LLVM_LIBC_FULL_BUILD AND NOT LIBC_TARGET_OS_IS_GPU)
freelist_heap_fuzz
SRCS
freelist_heap_fuzz.cpp
+ COMPILE_OPTIONS
+ -DLIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
DEPENDS
libc.src.__support.freelist_heap
)
diff --git a/libc/src/__support/block.h b/libc/src/__support/block.h
index be2a71f32a23f..83988070b9b95 100644
--- a/libc/src/__support/block.h
+++ b/libc/src/__support/block.h
@@ -100,8 +100,17 @@ using cpp::optional;
/// The first block in a list is denoted by having a previous offset of `0`.
class BlockRef {
// Masks for the contents of the next field.
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ static constexpr size_t PREV_FREE_MASK = 0x3; // 2 bits
+ static constexpr size_t LAST_MASK = 1 << 2; // bit 2
+
+ static constexpr size_t PREV_FREE_NONE = 0;
+ static constexpr size_t PREV_FREE_STORE_0 = 1;
+ static constexpr size_t PREV_FREE_STORE_1 = 2;
+#else
static constexpr size_t PREV_FREE_MASK = 1 << 0;
static constexpr size_t LAST_MASK = 1 << 1;
+#endif
static constexpr size_t SIZE_MASK = ~(PREV_FREE_MASK | LAST_MASK);
// Header field offsets. The value at PREV_OFFSET is only meaningful when the
@@ -115,7 +124,11 @@ class BlockRef {
// To ensure block sizes have two lower unused bits, ensure usable space is
// always aligned to at least 4 bytes. (The distances between usable spaces,
// the outer size, is then always also 4-aligned.)
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ static constexpr size_t MIN_ALIGN = cpp::max(size_t{8}, alignof(max_align_t));
+#else
static constexpr size_t MIN_ALIGN = cpp::max(size_t{4}, alignof(max_align_t));
+#endif
LIBC_INLINE constexpr BlockRef() = default;
LIBC_INLINE explicit constexpr BlockRef(cpp::byte *header_ptr)
@@ -232,11 +245,27 @@ class BlockRef {
/// @returns The free block immediately before this one, otherwise null.
LIBC_INLINE BlockRef prev_free() const {
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ if ((load_next() & PREV_FREE_MASK) == PREV_FREE_NONE)
+ return BlockRef();
+#else
if (!(load_next() & PREV_FREE_MASK))
return BlockRef();
+#endif
return BlockRef(nonnull_header_ptr() - load_prev());
}
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ LIBC_INLINE int prev_free_store_index() const {
+ size_t val = (load_next() & PREV_FREE_MASK);
+ if (val == PREV_FREE_STORE_0)
+ return 0;
+ if (val == PREV_FREE_STORE_1)
+ return 1;
+ return -1; // Not free
+ }
+#endif
+
/// @returns Whether the block is unavailable for allocation.
LIBC_INLINE bool used() const { return !next() || !next().prev_free(); }
@@ -248,12 +277,29 @@ class BlockRef {
}
/// Marks this block as free.
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ LIBC_INLINE void mark_free(int store_index) const {
+ LIBC_ASSERT(next() && "last block is always considered used");
+ BlockRef next_block = next();
+ size_t val = 0;
+ if (store_index == 0)
+ val = PREV_FREE_STORE_0;
+ else if (store_index == 1)
+ val = PREV_FREE_STORE_1;
+ LIBC_ASSERT(val != 0 && "Invalid store index");
+
+ size_t next_val = next_block.load_next() & ~PREV_FREE_MASK;
+ next_block.store_next(next_val | val);
+ next_block.store_prev(outer_size());
+ }
+#else
LIBC_INLINE void mark_free() const {
LIBC_ASSERT(next() && "last block is always considered used");
BlockRef next_block = next();
next_block.store_next(next_block.load_next() | PREV_FREE_MASK);
next_block.store_prev(outer_size());
}
+#endif
LIBC_INLINE bool is_usable_space_aligned(size_t alignment) const {
return reinterpret_cast<uintptr_t>(usable_space()) % alignment == 0;
@@ -439,7 +485,11 @@ optional<BlockRef> BlockRef::init(ByteSpan region) {
BlockRef block =
as_block({reinterpret_cast<cpp::byte *>(block_start), last_start_ptr});
make_last_block(last_start_ptr);
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ block.mark_free(0);
+#else
block.mark_free();
+#endif
return block;
}
@@ -460,6 +510,11 @@ BlockRef::BlockInfo BlockRef::allocate(BlockRef block, size_t alignment,
LIBC_ASSERT(maybe_aligned_block.has_value() &&
"it should always be possible to split for alignment");
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ // We skip eager merge here as we cannot tell the store index of original vs
+ // prev, but coalesce_and_insert will check and merge them if appropriate.
+ info.prev = original;
+#else
if (BlockRef prev = original.prev_free()) {
// If there is a free block before this, we can merge the current one with
// the newly created one.
@@ -467,6 +522,7 @@ BlockRef::BlockInfo BlockRef::allocate(BlockRef block, size_t alignment,
} else {
info.prev = original;
}
+#endif
BlockRef aligned_block = *maybe_aligned_block;
LIBC_ASSERT(aligned_block.is_usable_space_aligned(alignment) &&
@@ -505,14 +561,24 @@ optional<BlockRef> BlockRef::split(size_t new_inner_size,
return {};
bool was_free = !used();
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ int orig_store_idx = next().prev_free_store_index();
+ int store_to_set = orig_store_idx >= 0 ? orig_store_idx : 0;
+#endif
ByteSpan new_region = region().subspan(new_outer_size);
store_next((load_next() & ~SIZE_MASK) | new_outer_size);
BlockRef new_block = as_block(new_region);
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ new_block.mark_free(store_to_set);
+ if (was_free)
+ mark_free(store_to_set);
+#else
new_block.mark_free();
if (was_free)
mark_free();
+#endif
LIBC_ASSERT(new_block.is_usable_space_aligned(usable_space_alignment) &&
"usable space must have requested alignment");
diff --git a/libc/src/__support/freelist_heap.h b/libc/src/__support/freelist_heap.h
index d2ec9339d72ed..03d41737b372b 100644
--- a/libc/src/__support/freelist_heap.h
+++ b/libc/src/__support/freelist_heap.h
@@ -51,7 +51,14 @@ class FreeListHeap {
void *realloc(void *ptr, size_t size);
void *calloc(size_t num, size_t size);
size_t allocation_size(const void *ptr) const;
- LIBC_INLINE void integrity_check() const { free_store.integrity_check(); }
+ LIBC_INLINE void integrity_check() const {
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ free_stores[0].integrity_check();
+ free_stores[1].integrity_check();
+#else
+ free_store.integrity_check();
+#endif
+ }
cpp::span<cpp::byte> region() const { return {begin, end}; }
@@ -68,15 +75,68 @@ class FreeListHeap {
bool is_valid_ptr(const void *ptr) const { return ptr >= begin && ptr < end; }
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ LIBC_INLINE int get_store_index(BlockRef block) {
+ return block.next().prev_free_store_index();
+ }
+
+ LIBC_INLINE void coalesce_and_insert(BlockRef block, int store_idx) {
+ block.mark_free(store_idx);
+ BlockRef prev = block.prev_free();
+ if (prev) {
+ if (FreeStore::too_small(prev)) {
+ block = prev;
+ block.merge_next();
+ } else {
+ int prev_store = get_store_index(prev);
+ if (prev_store == store_idx) {
+ free_stores[prev_store].remove(prev);
+ block = prev;
+ block.merge_next();
+ }
+ }
+ }
+
+ BlockRef next = block.next();
+ if (!next.used()) {
+ if (FreeStore::too_small(next)) {
+ block.merge_next();
+ } else {
+ int next_store = get_store_index(next);
+ if (next_store == store_idx) {
+ free_stores[next_store].remove(next);
+ block.merge_next();
+ }
+ }
+ }
+ block.mark_free(store_idx);
+ free_stores[store_idx].insert(block);
+ }
+
+ LIBC_INLINE void rotate() {
+ unsigned prev_active = active;
+ active = 1 - active;
+ while (BlockRef block = free_stores[prev_active].remove_any())
+ coalesce_and_insert(block, active);
+ }
+#endif
+
cpp::byte *begin;
cpp::byte *end;
bool is_initialized = false;
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ FreeStore free_stores[2];
+ unsigned active = 0;
+ LIBC_INLINE FreeStore &active_free_store() { return free_stores[active]; }
+#else
FreeStore free_store;
+ LIBC_INLINE FreeStore &active_free_store() { return free_store; }
+#endif
};
template <size_t BUFF_SIZE> class FreeListHeapBuffer : public FreeListHeap {
public:
- constexpr FreeListHeapBuffer() : FreeListHeap{buffer}, buffer{} {}
+ LIBC_INLINE constexpr FreeListHeapBuffer() : FreeListHeap{buffer}, buffer{} {}
private:
cpp::byte buffer[BUFF_SIZE];
@@ -86,8 +146,14 @@ LIBC_INLINE void FreeListHeap::init() {
LIBC_ASSERT(!is_initialized && "duplicate initialization");
auto result = BlockRef::init(region());
BlockRef block = *result;
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ free_stores[0].set_range({0, cpp::bit_ceil(block.inner_size())});
+ free_stores[1].set_range({0, cpp::bit_ceil(block.inner_size())});
+ coalesce_and_insert(block, active);
+#else
free_store.set_range({0, cpp::bit_ceil(block.inner_size())});
free_store.insert(block);
+#endif
is_initialized = true;
}
@@ -102,17 +168,29 @@ LIBC_INLINE void *FreeListHeap::allocate_impl(size_t alignment, size_t size) {
if (!request_size)
return nullptr;
- BlockRef block = free_store.remove_best_fit(request_size);
+ BlockRef block = active_free_store().remove_best_fit(request_size);
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ if (!block) {
+ rotate();
+ block = active_free_store().remove_best_fit(request_size);
+ }
+#endif
if (!block)
return nullptr;
auto block_info = BlockRef::allocate(block, alignment, size);
+ block_info.block.mark_used();
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ if (block_info.next)
+ coalesce_and_insert(block_info.next, active);
+ if (block_info.prev)
+ coalesce_and_insert(block_info.prev, active);
+#else
if (block_info.next)
free_store.insert(block_info.next);
if (block_info.prev)
free_store.insert(block_info.prev);
-
- block_info.block.mark_used();
+#endif
return block_info.block.usable_space();
}
@@ -147,6 +225,9 @@ LIBC_INLINE void FreeListHeap::free(void *ptr) {
BlockRef block = BlockRef::from_usable_space(bytes);
LIBC_ASSERT(block.next() && "sentinel last block cannot be freed");
LIBC_ASSERT(block.used() && "double free");
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ coalesce_and_insert(block, 1 - active);
+#else
block.mark_free();
// Can we combine with the left or right blocks?
@@ -165,6 +246,7 @@ LIBC_INLINE void FreeListHeap::free(void *ptr) {
}
// Add back to the freelist
free_store.insert(block);
+#endif
}
LIBC_INLINE size_t FreeListHeap::allocation_size(const void *ptr) const {
@@ -186,6 +268,9 @@ LIBC_INLINE bool FreeListHeap::shrink_in_place(BlockRef block, size_t size) {
// register the new block on successful split
if (next.has_value()) {
BlockRef next_block = *next;
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ coalesce_and_insert(next_block, 1 - active);
+#else
BlockRef right = next_block.next();
// Since the original block was not the last block (the sentinel last
// block is never split), the split-off remainder block `next_block` is
@@ -197,6 +282,7 @@ LIBC_INLINE bool FreeListHeap::shrink_in_place(BlockRef block, size_t size) {
next_block.merge_next();
}
free_store.insert(next_block);
+#endif
}
return true;
}
diff --git a/libc/src/__support/freestore.h b/libc/src/__support/freestore.h
index ccc4f9555c64a..da440dd022872 100644
--- a/libc/src/__support/freestore.h
+++ b/libc/src/__support/freestore.h
@@ -73,6 +73,40 @@ template <typename CONFIG> class TLSFFreeStoreImpl {
list.integrity_check();
}
+ /// Removes and returns any block from the store.
+ /// @returns The block removed, or BlockRef() if empty.
+ LIBC_INLINE BlockRef remove_any() {
+ for (size_t i = 0; i < TOTAL_BITS - 1; ++i) {
+ if (!free_lists[i].empty()) {
+ BlockRef block = free_lists[i].front();
+ free_lists[i].pop();
+ if (free_lists[i].empty())
+ free_sizes.mark_vacant(i);
+ return block;
+ }
+ }
+ if constexpr (USE_TRIE) {
+ if (BlockRef block = trie.pop_any()) {
+ if (trie.empty())
+ free_sizes.mark_vacant(TOTAL_BITS - 1);
+ return block;
+ }
+ } else {
+ if (!overflow_list.empty()) {
+ BlockRef block = overflow_list.front();
+ overflow_list.pop();
+ if (overflow_list.empty())
+ free_sizes.mark_vacant(TOTAL_BITS - 1);
+ return block;
+ }
+ }
+ return BlockRef();
+ }
+
+ LIBC_INLINE static bool too_small(BlockRef block) {
+ return block.outer_size() < MIN_OUTER_SIZE;
+ }
+
private:
LIBC_INLINE constexpr TLSFFreeStoreImpl(cpp::bool_constant<true>) : trie() {}
LIBC_INLINE constexpr TLSFFreeStoreImpl(cpp::bool_constant<false>)
@@ -100,10 +134,6 @@ template <typename CONFIG> class TLSFFreeStoreImpl {
}
protected:
- LIBC_INLINE static bool too_small(BlockRef block) {
- return block.outer_size() < MIN_OUTER_SIZE;
- }
-
Table free_sizes;
cpp::array<FreeList, TOTAL_BITS - 1> free_lists;
union {
diff --git a/libc/src/__support/freetrie.cpp b/libc/src/__support/freetrie.cpp
index d0392342f2231..f15664db2f12f 100644
--- a/libc/src/__support/freetrie.cpp
+++ b/libc/src/__support/freetrie.cpp
@@ -79,4 +79,12 @@ void FreeTrie::integrity_check() const {
integrity_check_trie_node(integrity_check_trie_node, root());
}
+BlockRef FreeTrie::pop_any() {
+ if (!root_)
+ return BlockRef();
+ Node *node = root_;
+ remove(node);
+ return node->block();
+}
+
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/freetrie.h b/libc/src/__support/freetrie.h
index 1be34f456021b..bdb115eeb184b 100644
--- a/libc/src/__support/freetrie.h
+++ b/libc/src/__support/freetrie.h
@@ -132,6 +132,10 @@ class FreeTrie {
/// Verify integrity of all nodes in the trie.
void integrity_check() const;
+ /// Removes and returns any block from the trie.
+ /// @returns The block removed, or BlockRef() if empty.
+ BlockRef pop_any();
+
private:
/// @returns Whether a node is the head of its containing freelist.
bool is_head(Node *node) const { return node->parent || node == root_; }
diff --git a/libc/test/src/__support/block_test.cpp b/libc/test/src/__support/block_test.cpp
index 6bd0ab5be24c0..053e81b5313e2 100644
--- a/libc/test/src/__support/block_test.cpp
+++ b/libc/test/src/__support/block_test.cpp
@@ -249,7 +249,11 @@ TEST(LlvmLibcBlockTest, CanMarkBlockUsed) {
EXPECT_TRUE(block.used());
EXPECT_EQ(block.outer_size(), orig_size);
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ block.mark_free(0);
+#else
block.mark_free();
+#endif
EXPECT_FALSE(block.used());
}
@@ -469,7 +473,7 @@ TEST(LlvmLibcBlockTest, PreviousBlockMergedIfNotFirst) {
ASSERT_TRUE(result2.has_value());
BlockRef newblock = *result2;
ASSERT_EQ(newblock.prev_free().addr(), block.addr());
- size_t old_prev_size = block.outer_size();
+ [[maybe_unused]] size_t old_prev_size = block.outer_size();
// Now pick an alignment such that the usable space is not already aligned to
// it. We want to explicitly test that the block will split into one before
@@ -481,12 +485,18 @@ TEST(LlvmLibcBlockTest, PreviousBlockMergedIfNotFirst) {
// Ensure we can allocate in the new block.
auto [aligned_block, prev, next] = BlockRef::allocate(newblock, alignment, 1);
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ EXPECT_EQ(prev.addr(), newblock.addr());
+ EXPECT_EQ(aligned_block.prev_free().addr(), newblock.addr());
+ EXPECT_EQ(newblock.next().addr(), aligned_block.addr());
+#else
// Now there should be no new previous block. Instead, the padding we did
// create should be merged into the original previous block.
EXPECT_EQ(prev.addr(), BlockRef().addr());
EXPECT_EQ(aligned_block.prev_free().addr(), block.addr());
EXPECT_EQ(block.next().addr(), aligned_block.addr());
EXPECT_GT(block.outer_size(), old_prev_size);
+#endif
}
TEST(LlvmLibcBlockTest, CanRemergeBlockAllocations) {
diff --git a/libc/test/src/__support/freelist_heap_test.cpp b/libc/test/src/__support/freelist_heap_test.cpp
index 80b8131174459..3ac02f480e04e 100644
--- a/libc/test/src/__support/freelist_heap_test.cpp
+++ b/libc/test/src/__support/freelist_heap_test.cpp
@@ -97,8 +97,11 @@ TEST_FOR_EACH_ALLOCATOR(CanFreeAndRealloc, 2048) {
void *ptr1 = allocator.allocate(ALLOC_SIZE);
allocator.free(ptr1);
void *ptr2 = allocator.allocate(ALLOC_SIZE);
-
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+ EXPECT_NE(ptr1, ptr2);
+#else
EXPECT_EQ(ptr1, ptr2);
+#endif
}
TEST_FOR_EACH_ALLOCATOR(ReturnsNullWhenAllocationTooLarge, 2048) {
@@ -284,7 +287,7 @@ TEST_FOR_EACH_ALLOCATOR(AllocateZero, 2048) {
ASSERT_EQ(ptr, static_cast<void *>(nullptr));
}
-TEST_FOR_EACH_ALLOCATOR(AlignedAlloc, 2048) {
+TEST_FOR_EACH_ALLOCATOR(AlignedAlloc, 3072) {
constexpr size_t ALIGNMENTS[] = {1, 2, 4, 8, 16, 32, 64, 128, 256};
constexpr size_t SIZE_SCALES[] = {1, 2, 3, 4, 5};
@@ -305,7 +308,7 @@ TEST_FOR_EACH_ALLOCATOR(AlignedAlloc, 2048) {
// still get aligned allocations even if the underlying buffer is not aligned to
// the alignments we request.
TEST(LlvmLibcFreeListHeap, AlignedAllocUnalignedBuffer) {
- byte buf[4096] = {byte(0)};
+ byte buf[8192] = {byte(0)};
// Ensure the underlying buffer is poorly aligned.
FreeListHeap allocator(span<byte>(buf).subspan(1));
@@ -391,3 +394,33 @@ TEST_FOR_EACH_ALLOCATOR(IntegrityCheck, 2048) {
allocator.free(ptr2);
allocator.integrity_check();
}
+
+#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION
+TEST(LlvmLibcFreeListHeap, RotationSmokeTest) {
+ byte buf[4096] = {byte(0)};
+ FreeListHeap allocator(buf);
+
+ constexpr size_t SIZES[] = {64, 128, 256, 512};
+
+ for (size_t size : SIZES) {
+ void *ptr1 = allocator.alloc...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/209811
More information about the libc-commits
mailing list