| ... | @@ -64,9 +64,9 @@ const Header = packed struct(u64) { | ... | @@ -64,9 +64,9 @@ const Header = packed struct(u64) { |
| 64 | }; | 64 | }; |
| 65 | | 65 | |
| 66 | fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { | 66 | fn 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 | } |
| 79 | | 79 | |
| 80 | fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { | 80 | fn 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`. |
| | 85 | fn 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 | } |
| 95 | | 100 | |
| 96 | fn calloc(elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { | 101 | fn 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 | } |
| 140 | | 146 | |
| 141 | fn reallocarray(opt_base: ?[*]align(alignment_bytes) u8, elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { | 147 | fn 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 | } |
| 145 | | 151 | |
| ... | @@ -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 |
| 173 | | 179 | |
| 174 | fn posix_memalign(result: *?[*]align(alignment_bytes) u8, alloc_alignment: usize, n: usize) callconv(.c) c_int { | 180 | fn 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`. |
| | 188 | fn nomem() ?[*]align(alignment_bytes) u8 { |
| | 189 | @branchHint(.cold); |
| | 190 | std.c._errno().* = @intFromEnum(std.c.E.NOMEM); |
| | 191 | return null; |
| | 192 | } |