Skip to content

Commit 13cccdd

Browse files
committed
add std.heap.raw_c_allocator
This API does what `std.heap.c_allocator` previously did. See the new doc comments for more details.
1 parent 02a4e5a commit 13cccdd

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

lib/std/c.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,13 @@ pub extern "c" fn prctl(option: c_int, ...) c_int;
332332

333333
pub extern "c" fn getrlimit(resource: rlimit_resource, rlim: *rlimit) c_int;
334334
pub extern "c" fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) c_int;
335+
336+
pub const max_align_t = if (std.Target.current.abi == .msvc)
337+
f64
338+
else if (std.Target.current.isDarwin())
339+
c_longdouble
340+
else
341+
extern struct {
342+
a: c_longlong,
343+
b: c_longdouble,
344+
};

lib/std/heap.zig

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,56 @@ const CAllocator = struct {
148148
}
149149
};
150150

151+
/// Supports the full Allocator interface, including alignment, and exploiting
152+
/// `malloc_usable_size` if available. For an allocator that directly calls
153+
/// `malloc`/`free`, see `raw_c_allocator`.
151154
pub const c_allocator = &c_allocator_state;
152155
var c_allocator_state = Allocator{
153156
.allocFn = CAllocator.alloc,
154157
.resizeFn = CAllocator.resize,
155158
};
156159

160+
/// Asserts allocations are within `@alignOf(std.c.max_align_t)` and directly calls
161+
/// `malloc`/`free`. Does not attempt to utilize `malloc_usable_size`.
162+
/// This allocator is safe to use as the backing allocator with
163+
/// `ArenaAllocator` and `GeneralPurposeAllocator`, and is more optimal in these cases
164+
/// than to using `c_allocator`.
165+
pub const raw_c_allocator = &raw_c_allocator_state;
166+
var raw_c_allocator_state = Allocator{
167+
.allocFn = rawCAlloc,
168+
.resizeFn = rawCResize,
169+
};
170+
171+
fn rawCAlloc(
172+
self: *Allocator,
173+
len: usize,
174+
ptr_align: u29,
175+
len_align: u29,
176+
ret_addr: usize,
177+
) Allocator.Error![]u8 {
178+
assert(ptr_align <= @alignOf(std.c.max_align_t));
179+
const ptr = @ptrCast([*]u8, c.malloc(len) orelse return error.OutOfMemory);
180+
return ptr[0..len];
181+
}
182+
183+
fn rawCResize(
184+
self: *Allocator,
185+
buf: []u8,
186+
old_align: u29,
187+
new_len: usize,
188+
len_align: u29,
189+
ret_addr: usize,
190+
) Allocator.Error!usize {
191+
if (new_len == 0) {
192+
c.free(buf.ptr);
193+
return 0;
194+
}
195+
if (new_len <= buf.len) {
196+
return mem.alignAllocLen(buf.len, new_len, len_align);
197+
}
198+
return error.OutOfMemory;
199+
}
200+
157201
/// This allocator makes a syscall directly for every allocation and free.
158202
/// Thread-safe and lock-free.
159203
pub const page_allocator = if (std.Target.current.isWasm())
@@ -804,6 +848,12 @@ test "c_allocator" {
804848
}
805849
}
806850

851+
test "raw_c_allocator" {
852+
if (builtin.link_libc) {
853+
try testAllocator(raw_c_allocator);
854+
}
855+
}
856+
807857
test "WasmPageAllocator internals" {
808858
if (comptime std.Target.current.isWasm()) {
809859
const conventional_memsize = WasmPageAllocator.conventional.totalPages() * mem.page_size;
@@ -958,6 +1008,7 @@ test "ThreadSafeFixedBufferAllocator" {
9581008
try testAllocatorAlignedShrink(&fixed_buffer_allocator.allocator);
9591009
}
9601010

1011+
/// This one should not try alignments that exceed what C malloc can handle.
9611012
pub fn testAllocator(base_allocator: *mem.Allocator) !void {
9621013
var validationAllocator = mem.validationWrap(base_allocator);
9631014
const allocator = &validationAllocator.allocator;

src/main.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub fn log(
103103
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
104104

105105
pub fn main() anyerror!void {
106-
const gpa = if (std.builtin.link_libc) std.heap.c_allocator else &general_purpose_allocator.allocator;
106+
const gpa = if (std.builtin.link_libc) std.heap.raw_c_allocator else &general_purpose_allocator.allocator;
107107
defer if (!std.builtin.link_libc) {
108108
_ = general_purpose_allocator.deinit();
109109
};

0 commit comments

Comments
 (0)