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) {...@@ -64,9 +64,9 @@ const Header = packed struct(u64) {
64};64};
6565
66fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {66fn 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();
68 const ptr: [*]align(alignment_bytes) u8 = @alignCast(68 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(),
70 );70 );
71 const base = ptr + alignment_bytes;71 const base = ptr + alignment_bytes;
72 const header: *Header = .fromBase(base);72 const header: *Header = .fromBase(base);
...@@ -78,6 +78,11 @@ fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {...@@ -78,6 +78,11 @@ fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {
78}78}
7979
80fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {80fn 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 {
81 const size = std.math.cast(Header.Size, n) orelse return null;86 const size = std.math.cast(Header.Size, n) orelse return null;
82 const max_align = alignment.max(.fromByteUnits(alloc_alignment));87 const max_align = alignment.max(.fromByteUnits(alloc_alignment));
83 const max_align_bytes = max_align.toByteUnits();88 const max_align_bytes = max_align.toByteUnits();
...@@ -94,7 +99,7 @@ fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignm...@@ -94,7 +99,7 @@ fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignm
94}99}
95100
96fn calloc(elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {101fn 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();
98 const base = malloc(n) orelse return null;103 const base = malloc(n) orelse return null;
99 @memset(base[0..n], 0);104 @memset(base[0..n], 0);
100 return base;105 return base;
...@@ -106,7 +111,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?...@@ -106,7 +111,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
106 return null;111 return null;
107 }112 }
108 const old_base = opt_old_base orelse return malloc(n);113 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();
110 const old_header: *Header = .fromBase(old_base);115 const old_header: *Header = .fromBase(old_base);
111 assert(old_header.padding == 0);116 assert(old_header.padding == 0);
112 const old_size = old_header.size;117 const old_size = old_header.size;
...@@ -122,7 +127,8 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?...@@ -122,7 +127,8 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
122 no_ra,127 no_ra,
123 )) |new_ptr| @alignCast(new_ptr + old_alignment_bytes) else b: {128 )) |new_ptr| @alignCast(new_ptr + old_alignment_bytes) else b: {
124 const new_ptr: [*]align(alignment_bytes) u8 = @alignCast(129 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(),
126 );132 );
127 const new_base: [*]align(alignment_bytes) u8 = @alignCast(new_ptr + old_alignment_bytes);133 const new_base: [*]align(alignment_bytes) u8 = @alignCast(new_ptr + old_alignment_bytes);
128 const copy_len = @min(new_size, old_size);134 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) ?...@@ -139,7 +145,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ?
139}145}
140146
141fn reallocarray(opt_base: ?[*]align(alignment_bytes) u8, elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 {147fn 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();
143 return realloc(opt_base, n);149 return realloc(opt_base, n);
144}150}
145151
...@@ -173,10 +179,14 @@ fn memalign(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_b...@@ -173,10 +179,14 @@ fn memalign(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_b
173179
174fn posix_memalign(result: *?[*]align(alignment_bytes) u8, alloc_alignment: usize, n: usize) callconv(.c) c_int {180fn posix_memalign(result: *?[*]align(alignment_bytes) u8, alloc_alignment: usize, n: usize) callconv(.c) c_int {
175 if (alloc_alignment < @sizeOf(*anyopaque)) return @intFromEnum(std.c.E.INVAL);181 if (alloc_alignment < @sizeOf(*anyopaque)) return @intFromEnum(std.c.E.INVAL);
176 if (n == 0) {182 result.* = aligned_alloc_inner(alloc_alignment, n) orelse return @intFromEnum(std.c.E.NOMEM);
177 result.* = null;
178 } else {
179 result.* = aligned_alloc(alloc_alignment, n) orelse return @intFromEnum(std.c.E.NOMEM);
180 }
181 return 0;183 return 0;
182}184}
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}