-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[libc][malloc] Ensure a minimum block alignment of 4 #169447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-libc Author: Daniel Thornburgh (mysterymath) ChangesMost platforms inherently have a size_t alignment of 4, but this isn't true on every platform LLVM has some degree of backend support for. Accordingly, it's simple enough to just set the min alignment of Block to 4 and lose the static_assert. Full diff: https://github.com/llvm/llvm-project/pull/169447.diff 1 Files Affected:
diff --git a/libc/src/__support/block.h b/libc/src/__support/block.h
index b0d6576093244..faab409166c6e 100644
--- a/libc/src/__support/block.h
+++ b/libc/src/__support/block.h
@@ -90,7 +90,10 @@ using cpp::optional;
///
/// The next offset of a block matches the previous offset of its next block.
/// The first block in a list is denoted by having a previous offset of `0`.
-class Block {
+///
+// Ensure a minimum alignment of 4, since at least 2 bits must be available in
+// block sizes for flags.
+class alignas(cpp::max(alignof(size_t), size_t{4})) Block {
// Masks for the contents of the next_ field.
static constexpr size_t PREV_FREE_MASK = 1 << 0;
static constexpr size_t LAST_MASK = 1 << 1;
@@ -360,9 +363,6 @@ class Block {
static constexpr size_t PREV_FIELD_SIZE = sizeof(prev_);
};
-static_assert(alignof(Block) >= 4,
- "at least 2 bits must be available in block sizes for flags");
-
LIBC_INLINE
optional<Block *> Block::init(ByteSpan region) {
if (!region.data())
|
|
@mysterymath shouldn't it be better to align block to |
|
The consensus around allocation alignments is a little weird, its not specified in the standard anywhere. Generally, dynamic memory is supposed to be aligned to the largest memory required by a primitive type, i.e. |
|
But would that be against C11 standard? POSIX standard (issue 8) says "The pointer returned if the allocation succeeds shall be suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object in the space allocated" ISO/IEC 9899:201X says "A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(max_align_t)." I know the standard is a bit awkward as we do have I understand that many platforms we support have considerations of limited space. We can document and opt-in this on baremetal and gpu, align with standard otherwise unless the user opt-in a different minimal alignment. |
|
It seems that some modern allocators (e.g. mimalloc) does relax this for allocation sizes less than |
|
Aha, didn't think this would trigger much discussion! This is specifically for the alignment of the Block structure, but the way we've implemented things, that actually has only indirect bearing on the alignment of the returned pointers carved out of blocks, as Block locations are adjusted such that the ends of the block headers (i.e., the ends of the Block structs) are always aligned to max_align_t. (In particular, this means that Blocks themselves might be required to never align to max_align_t!) The only alignment requirements for Block itself are that it be correctly alignment for its contents (two size_t), and that it be aligned to at least 4, so that the bottom two bits of block sizes are always logically zero and thus free to store flags. It must also be the case that max_align_t is a multiple of the block alignment, but that's true for any power of two. |
|
Drafting this for now; I just realized from the above that the sizes are the important thing now; the Block alignment itself is somewhat immaterial, as Block placement is completely controlled by the Block init functions. Some of this logic bled through from the older implementation, and it doesn't quite make sense after I had refactored it, so I'll need to do a bit more surgery to make this internally consistent. |
d74bdfa to
84e1c3b
Compare
|
Alright, I've updated this to directly ensure that the usable space alignment within the block is 4 at minimum. This may waste a bit of space, but it's quite simpler, and it would only have any effect on platforms where |
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Most platforms inherently have a size_t alignment of 4, but this isn't true on every platform LLVM has some degree of backend support for. Accordingly, it's simple enough to just set the min alignment of each Block's usable space to 4 and lose the static_assert.
84e1c3b to
4f9cd6e
Compare
Most platforms inherently have a size_t alignment of 4, but this isn't true on every platform LLVM has some degree of backend support for. Accordingly, it's simple enough to just set the min alignment of Block to 4 and lose the static_assert.