authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-11 23:49:21-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-12 13:14:51-08:00
logec02571a30e2975039cef5cb92467082ea5de5c0
treea5d18de88e20971d50f5d82d9913cfda71074e98
parent0de7668c013c5d3e095f0e436dba1b22a6a01f14

zig libc malloc: set errno when returning null


1 files changed, 21 insertions(+), 11 deletions(-)

lib/c/malloc.zig+21-11
......@@ -64,9 +64,9 @@ const Header = packed struct(u64) {
6464};
6565
6666fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
67 const size = std.math.cast(Header.Size, n) orelse return null;
67 const size = std.math.cast(Header.Size, n) orelse return nomem();
6868 const ptr: [*]align(alignment_bytes) u8 = @alignCast(
69 vtable.alloc(no_context, n + alignment_bytes, alignment, no_ra) orelse return null,
69 vtable.alloc(no_context, n + alignment_bytes, alignment, no_ra) orelse return nomem(),
7070 );
7171 const base = ptr + alignment_bytes;
7272 const header: *Header = .fromBase(base);
......@@ -78,6 +78,11 @@ fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
7878}
7979
8080fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
81 return aligned_alloc_inner(alloc_alignment, n) orelse return nomem();
82}
83
84/// Avoids setting errno so it can be called by `posix_memalign`.
85fn aligned_alloc_inner(alloc_alignment: usize, n: usize) ?[*]align(alignment_bytes) u8 {
8186 const size = std.math.cast(Header.Size, n) orelse return null;
8287 const max_align = alignment.max(.fromByteUnits(alloc_alignment));
8388 const max_align_bytes = max_align.toByteUnits();
......@@ -94,7 +99,7 @@ fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignm
9499}
95100
96101fn calloc(elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
97 const n = std.math.mul(usize, elems, len) catch return null;
102 const n = std.math.mul(usize, elems, len) catch return nomem();
98103 const base = malloc(n) orelse return null;
99104 @memset(base[0..n], 0);
100105 return base;
......@@ -106,7 +111,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
106111 return null;
107112 }
108113 const old_base = opt_old_base orelse return malloc(n);
109 const new_size = std.math.cast(Header.Size, n) orelse return null;
114 const new_size = std.math.cast(Header.Size, n) orelse return nomem();
110115 const old_header: *Header = .fromBase(old_base);
111116 assert(old_header.padding == 0);
112117 const old_size = old_header.size;
......@@ -122,7 +127,8 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
122127 no_ra,
123128 )) |new_ptr| @alignCast(new_ptr + old_alignment_bytes) else b: {
124129 const new_ptr: [*]align(alignment_bytes) u8 = @alignCast(
125 vtable.alloc(no_context, n + old_alignment_bytes, old_alignment, no_ra) orelse return null,
130 vtable.alloc(no_context, n + old_alignment_bytes, old_alignment, no_ra) orelse
131 return nomem(),
126132 );
127133 const new_base: [*]align(alignment_bytes) u8 = @alignCast(new_ptr + old_alignment_bytes);
128134 const copy_len = @min(new_size, old_size);
......@@ -139,7 +145,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
139145}
140146
141147fn reallocarray(opt_base: ?[*]align(alignment_bytes) u8, elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
142 const n = std.math.mul(usize, elems, len) catch return null;
148 const n = std.math.mul(usize, elems, len) catch return nomem();
143149 return realloc(opt_base, n);
144150}
145151
......@@ -173,10 +179,14 @@ fn memalign(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_b
173179
174180fn posix_memalign(result: *?[*]align(alignment_bytes) u8, alloc_alignment: usize, n: usize) callconv(.c) c_int {
175181 if (alloc_alignment < @sizeOf(*anyopaque)) return @intFromEnum(std.c.E.INVAL);
176 if (n == 0) {
177 result.* = null;
178 } else {
179 result.* = aligned_alloc(alloc_alignment, n) orelse return @intFromEnum(std.c.E.NOMEM);
180 }
182 result.* = aligned_alloc_inner(alloc_alignment, n) orelse return @intFromEnum(std.c.E.NOMEM);
181183 return 0;
182184}
185
186/// Libc memory allocation functions must set errno in addition to returning
187/// `null`.
188fn nomem() ?[*]align(alignment_bytes) u8 {
189 @branchHint(.cold);
190 std.c._errno().* = @intFromEnum(std.c.E.NOMEM);
191 return null;
192}