commit b5ff96b4d2091a29c07671e814fa937d2902e9b9 (tree)
parent db15df5daa3e5e93ff1085e7a43999f0bb61938b
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Sat, 6 Dec 2025 08:08:06 +0000
std.heap: remove `raw_c_allocator`
After https://codeberg.org/ziglang/zig/pulls/30103, `raw_c_allocator` is
redundant. It existed to avoid overhead when you could assert that all
of your `Allocator` usage was going to be compatible with the C `malloc`
API, but the standard `c_allocator` is now able to avoid that overhead
*in the case* that your usage is compatible (and use the less efficient
path in the rare case where it's not), so there's no need for the raw
version anymore. Leaving it in `std.heap` at this point seems like it
would just be a footgun.
Diffstat:
2 files changed, 14 insertions(+), 95 deletions(-)
diff --git a/lib/compiler/aro/main.zig b/lib/compiler/aro/main.zig
@@ -19,7 +19,7 @@ var debug_allocator: std.heap.DebugAllocator(.{
pub fn main() u8 {
const gpa = if (@import("builtin").link_libc)
- std.heap.raw_c_allocator
+ std.heap.c_allocator
else
debug_allocator.allocator();
defer if (!@import("builtin").link_libc) {
diff --git a/lib/std/heap.zig b/lib/std/heap.zig
@@ -146,9 +146,6 @@ test defaultQueryPageSize {
/// possible, but large requested alignments may require larger buffers in order to
/// satisfy the request. As well as `malloc`, `realloc`, and `free`, the extension
/// functions `malloc_usable_size` and `posix_memalign` are used when available.
-///
-/// For an allocator that directly calls `malloc`/`realloc`/`free`, with no padding
-/// or special handling, see `raw_c_allocator`.
pub const c_allocator: Allocator = .{
.ptr = undefined,
.vtable = &c_allocator_impl.vtable,
@@ -228,8 +225,19 @@ const c_allocator_impl = struct {
assert(len > 0);
switch (allocStrat(alignment)) {
.raw => {
- // C only needs to respect `max_align_t` up to the allocation size due to object
- // alignment rules. If necessary, extend the allocation size.
+ // `std.c.max_align_t` isn't the whole story, because if `len` is smaller than
+ // every C type with alignment `max_align_t`, the allocation can be less-aligned.
+ // The implementation need only guarantee that any type of length `len` would be
+ // suitably aligned.
+ //
+ // For instance, if `len == 8` and `alignment == .@"16"`, then `malloc` may not
+ // fulfil this request, because there is necessarily no C type with 8-byte size
+ // but 16-byte alignment.
+ //
+ // In theory, the resulting rule here would be target-specific, but in practice,
+ // the smallest type with an alignment of `max_align_t` has the same size (it's
+ // usually `c_longdouble`), so we can just extend the allocation size up to the
+ // alignment of `max_align_t` if necessary.
const actual_len = @max(len, @alignOf(std.c.max_align_t));
const ptr = c.malloc(actual_len) orelse return null;
assert(alignment.check(@intFromPtr(ptr)));
@@ -334,89 +342,6 @@ const c_allocator_impl = struct {
}
};
-/// Asserts that allocations have alignments which `malloc` can satisfy. This means that
-/// the requested alignment is no greater than `@min(@alignOf(std.c.max_align_t), size)`.
-///
-/// This allocator is rarely appropriate to use. In general, prefer `c_allocator`, which
-/// does not have any special requirements of its input, but is still highly efficient for
-/// allocation requests which obey `malloc` alignment rules.
-pub const raw_c_allocator: Allocator = .{
- .ptr = undefined,
- .vtable = &raw_c_allocator_vtable,
-};
-const raw_c_allocator_vtable: Allocator.VTable = .{
- .alloc = rawCAlloc,
- .resize = rawCResize,
- .remap = rawCRemap,
- .free = rawCFree,
-};
-
-fn rawCAlloc(
- context: *anyopaque,
- len: usize,
- alignment: Alignment,
- return_address: usize,
-) ?[*]u8 {
- _ = context;
- _ = return_address;
- // `std.c.max_align_t` isn't the whole story, because if `len` is smaller than
- // every C type with alignment `max_align_t`, the allocation can be less-aligned.
- // The implementation need only guarantee that any type of length `len` would be
- // suitably aligned.
- //
- // For instance, if `len == 8` and `alignment == .@"16"`, then `malloc` may not
- // fulfil this request, because there is necessarily no C type with 8-byte size
- // but 16-byte alignment.
- //
- // In theory, the resulting rule here would be target-specific, but in practice,
- // the smallest type with an alignment of `max_align_t` has the same size (it's
- // usually `c_longdouble`), so we can just check that `alignment <= len`.
- assert(alignment.toByteUnits() <= len);
- assert(Alignment.compare(alignment, .lte, .of(std.c.max_align_t)));
- return @ptrCast(c.malloc(len));
-}
-
-fn rawCResize(
- context: *anyopaque,
- memory: []u8,
- alignment: Alignment,
- new_len: usize,
- return_address: usize,
-) bool {
- _ = context;
- _ = memory;
- _ = alignment;
- _ = new_len;
- _ = return_address;
- return false;
-}
-
-fn rawCRemap(
- context: *anyopaque,
- memory: []u8,
- alignment: Alignment,
- new_len: usize,
- return_address: usize,
-) ?[*]u8 {
- _ = context;
- _ = return_address;
- // See `rawCMalloc` for an explanation of this `assert` call.
- assert(alignment.toByteUnits() <= new_len);
- return @ptrCast(c.realloc(memory.ptr, new_len));
-}
-
-fn rawCFree(
- context: *anyopaque,
- memory: []u8,
- alignment: Alignment,
- return_address: usize,
-) void {
- _ = context;
- _ = alignment;
- _ = return_address;
- c.free(memory.ptr);
-}
-
/// On operating systems that support memory mapping, this allocator makes a
/// syscall directly for every allocation and free.
///
@@ -569,12 +494,6 @@ test c_allocator {
}
}
-test raw_c_allocator {
- if (builtin.link_libc) {
- try testAllocator(raw_c_allocator);
- }
-}
-
test smp_allocator {
if (builtin.single_threaded) return;
try testAllocator(smp_allocator);