authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-12-06 08:08:06+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-12-06 22:08:40+01:00
logb5ff96b4d2091a29c07671e814fa937d2902e9b9
treedfdc99e2fb0432bd8a5d3a940a8aa501a6a3d69a
parentdb15df5daa3e5e93ff1085e7a43999f0bb61938b

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.

2 files changed, 14 insertions(+), 95 deletions(-)

lib/compiler/aro/main.zig+1-1
......@@ -19,7 +19,7 @@ var debug_allocator: std.heap.DebugAllocator(.{
1919
2020pub fn main() u8 {
2121 const gpa = if (@import("builtin").link_libc)
22 std.heap.raw_c_allocator
22 std.heap.c_allocator
2323 else
2424 debug_allocator.allocator();
2525 defer if (!@import("builtin").link_libc) {
lib/std/heap.zig+13-94
......@@ -146,9 +146,6 @@ test defaultQueryPageSize {
146146/// possible, but large requested alignments may require larger buffers in order to
147147/// satisfy the request. As well as `malloc`, `realloc`, and `free`, the extension
148148/// functions `malloc_usable_size` and `posix_memalign` are used when available.
149///
150/// For an allocator that directly calls `malloc`/`realloc`/`free`, with no padding
151/// or special handling, see `raw_c_allocator`.
152149pub const c_allocator: Allocator = .{
153150 .ptr = undefined,
154151 .vtable = &c_allocator_impl.vtable,
......@@ -228,8 +225,19 @@ const c_allocator_impl = struct {
228225 assert(len > 0);
229226 switch (allocStrat(alignment)) {
230227 .raw => {
231 // C only needs to respect `max_align_t` up to the allocation size due to object
232 // alignment rules. If necessary, extend the allocation size.
228 // `std.c.max_align_t` isn't the whole story, because if `len` is smaller than
229 // every C type with alignment `max_align_t`, the allocation can be less-aligned.
230 // The implementation need only guarantee that any type of length `len` would be
231 // suitably aligned.
232 //
233 // For instance, if `len == 8` and `alignment == .@"16"`, then `malloc` may not
234 // fulfil this request, because there is necessarily no C type with 8-byte size
235 // but 16-byte alignment.
236 //
237 // In theory, the resulting rule here would be target-specific, but in practice,
238 // the smallest type with an alignment of `max_align_t` has the same size (it's
239 // usually `c_longdouble`), so we can just extend the allocation size up to the
240 // alignment of `max_align_t` if necessary.
233241 const actual_len = @max(len, @alignOf(std.c.max_align_t));
234242 const ptr = c.malloc(actual_len) orelse return null;
235243 assert(alignment.check(@intFromPtr(ptr)));
......@@ -334,89 +342,6 @@ const c_allocator_impl = struct {
334342 }
335343};
336344
337/// Asserts that allocations have alignments which `malloc` can satisfy. This means that
338/// the requested alignment is no greater than `@min(@alignOf(std.c.max_align_t), size)`.
339///
340/// This allocator is rarely appropriate to use. In general, prefer `c_allocator`, which
341/// does not have any special requirements of its input, but is still highly efficient for
342/// allocation requests which obey `malloc` alignment rules.
343pub const raw_c_allocator: Allocator = .{
344 .ptr = undefined,
345 .vtable = &raw_c_allocator_vtable,
346};
347const raw_c_allocator_vtable: Allocator.VTable = .{
348 .alloc = rawCAlloc,
349 .resize = rawCResize,
350 .remap = rawCRemap,
351 .free = rawCFree,
352};
353
354fn rawCAlloc(
355 context: *anyopaque,
356 len: usize,
357 alignment: Alignment,
358 return_address: usize,
359) ?[*]u8 {
360 _ = context;
361 _ = return_address;
362 // `std.c.max_align_t` isn't the whole story, because if `len` is smaller than
363 // every C type with alignment `max_align_t`, the allocation can be less-aligned.
364 // The implementation need only guarantee that any type of length `len` would be
365 // suitably aligned.
366 //
367 // For instance, if `len == 8` and `alignment == .@"16"`, then `malloc` may not
368 // fulfil this request, because there is necessarily no C type with 8-byte size
369 // but 16-byte alignment.
370 //
371 // In theory, the resulting rule here would be target-specific, but in practice,
372 // the smallest type with an alignment of `max_align_t` has the same size (it's
373 // usually `c_longdouble`), so we can just check that `alignment <= len`.
374 assert(alignment.toByteUnits() <= len);
375 assert(Alignment.compare(alignment, .lte, .of(std.c.max_align_t)));
376 return @ptrCast(c.malloc(len));
377}
378
379fn rawCResize(
380 context: *anyopaque,
381 memory: []u8,
382 alignment: Alignment,
383 new_len: usize,
384 return_address: usize,
385) bool {
386 _ = context;
387 _ = memory;
388 _ = alignment;
389 _ = new_len;
390 _ = return_address;
391 return false;
392}
393
394fn rawCRemap(
395 context: *anyopaque,
396 memory: []u8,
397 alignment: Alignment,
398 new_len: usize,
399 return_address: usize,
400) ?[*]u8 {
401 _ = context;
402 _ = return_address;
403 // See `rawCMalloc` for an explanation of this `assert` call.
404 assert(alignment.toByteUnits() <= new_len);
405 return @ptrCast(c.realloc(memory.ptr, new_len));
406}
407
408fn rawCFree(
409 context: *anyopaque,
410 memory: []u8,
411 alignment: Alignment,
412 return_address: usize,
413) void {
414 _ = context;
415 _ = alignment;
416 _ = return_address;
417 c.free(memory.ptr);
418}
419
420345/// On operating systems that support memory mapping, this allocator makes a
421346/// syscall directly for every allocation and free.
422347///
......@@ -569,12 +494,6 @@ test c_allocator {
569494 }
570495}
571496
572test raw_c_allocator {
573 if (builtin.link_libc) {
574 try testAllocator(raw_c_allocator);
575 }
576}
577
578497test smp_allocator {
579498 if (builtin.single_threaded) return;
580499 try testAllocator(smp_allocator);