| ... | ... | @@ -52,17 +52,37 @@ const Header = packed struct(u64) { |
| 52 | 52 | alignment: Alignment, |
| 53 | 53 | /// Does not include the extra alignment bytes added. |
| 54 | 54 | size: Size, |
| 55 | | padding: Padding = 0, |
| 55 | canary: Canary = magic, |
| 56 | 56 | |
| 57 | 57 | comptime { |
| 58 | 58 | assert(@sizeOf(Header) <= alignment_bytes); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | | const Size = @Int(.unsigned, @min(64 - @bitSizeOf(Alignment), @bitSizeOf(usize))); |
| 62 | | const Padding = @Int(.unsigned, 64 - @bitSizeOf(Alignment) - @bitSizeOf(Size)); |
| 61 | const safety = switch (builtin.mode) { |
| 62 | .Debug, .ReleaseSafe => true, |
| 63 | .ReleaseFast, .ReleaseSmall => false, |
| 64 | }; |
| 65 | const max_addr_bits = switch (safety) { |
| 66 | true => 48, // Ensures space for Canary bits. |
| 67 | false => 64, |
| 68 | }; |
| 69 | const Size = @Int(.unsigned, @min(max_addr_bits, 64 - @bitSizeOf(Alignment), @bitSizeOf(usize))); |
| 70 | const Canary = @Int(.unsigned, 64 - @bitSizeOf(Alignment) - @bitSizeOf(Size)); |
| 71 | const magic: Canary = switch (safety) { |
| 72 | true => @truncate(@as(u64, 0x76fa65bebb3d7a39)), // statically chosen entropy |
| 73 | false => 0, |
| 74 | }; |
| 75 | |
| 76 | fn get(base: [*]align(alignment_bytes) u8) Header { |
| 77 | const header: *Header = @ptrCast(base - @sizeOf(Header)); |
| 78 | assert(header.canary == magic); |
| 79 | return header.*; |
| 80 | } |
| 63 | 81 | |
| 64 | | fn fromBase(base: [*]align(alignment_bytes) u8) *Header { |
| 65 | | return @ptrCast(base - @sizeOf(Header)); |
| 82 | fn set(base: [*]align(alignment_bytes) u8, a: Alignment, size: Size) [*]align(alignment_bytes) u8 { |
| 83 | const header: *Header = @ptrCast(base - @sizeOf(Header)); |
| 84 | header.* = .{ .alignment = a, .size = size }; |
| 85 | return base; |
| 66 | 86 | } |
| 67 | 87 | }; |
| 68 | 88 | |
| ... | ... | @@ -72,12 +92,7 @@ fn malloc(n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { |
| 72 | 92 | vtable.alloc(no_context, n + alignment_bytes, alignment, no_ra) orelse return nomem(), |
| 73 | 93 | ); |
| 74 | 94 | const base = ptr + alignment_bytes; |
| 75 | | const header: *Header = .fromBase(base); |
| 76 | | header.* = .{ |
| 77 | | .alignment = alignment, |
| 78 | | .size = size, |
| 79 | | }; |
| 80 | | return base; |
| 95 | return Header.set(base, alignment, size); |
| 81 | 96 | } |
| 82 | 97 | |
| 83 | 98 | fn aligned_alloc(alloc_alignment: usize, n: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { |
| ... | ... | @@ -93,12 +108,7 @@ fn aligned_alloc_inner(alloc_alignment: usize, n: usize) ?[*]align(alignment_byt |
| 93 | 108 | vtable.alloc(no_context, n + max_align_bytes, max_align, no_ra) orelse return null, |
| 94 | 109 | ); |
| 95 | 110 | const base: [*]align(alignment_bytes) u8 = @alignCast(ptr + max_align_bytes); |
| 96 | | const header: *Header = .fromBase(base); |
| 97 | | header.* = .{ |
| 98 | | .alignment = max_align, |
| 99 | | .size = size, |
| 100 | | }; |
| 101 | | return base; |
| 111 | return Header.set(base, max_align, size); |
| 102 | 112 | } |
| 103 | 113 | |
| 104 | 114 | fn calloc(elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { |
| ... | ... | @@ -115,8 +125,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ? |
| 115 | 125 | } |
| 116 | 126 | const old_base = opt_old_base orelse return malloc(n); |
| 117 | 127 | const new_size = std.math.cast(Header.Size, n) orelse return nomem(); |
| 118 | | const old_header: *Header = .fromBase(old_base); |
| 119 | | assert(old_header.padding == 0); |
| 128 | const old_header: Header = .get(old_base); |
| 120 | 129 | const old_size = old_header.size; |
| 121 | 130 | const old_alignment = old_header.alignment; |
| 122 | 131 | const old_alignment_bytes = old_alignment.toByteUnits(); |
| ... | ... | @@ -139,12 +148,7 @@ fn realloc(opt_old_base: ?[*]align(alignment_bytes) u8, n: usize) callconv(.c) ? |
| 139 | 148 | vtable.free(no_context, old_slice, old_alignment, no_ra); |
| 140 | 149 | break :b new_base; |
| 141 | 150 | }; |
| 142 | | const new_header: *Header = .fromBase(new_base); |
| 143 | | new_header.* = .{ |
| 144 | | .alignment = old_alignment, |
| 145 | | .size = new_size, |
| 146 | | }; |
| 147 | | return new_base; |
| 151 | return Header.set(new_base, old_alignment, new_size); |
| 148 | 152 | } |
| 149 | 153 | |
| 150 | 154 | fn reallocarray(opt_base: ?[*]align(alignment_bytes) u8, elems: usize, len: usize) callconv(.c) ?[*]align(alignment_bytes) u8 { |
| ... | ... | @@ -154,8 +158,7 @@ fn reallocarray(opt_base: ?[*]align(alignment_bytes) u8, elems: usize, len: usiz |
| 154 | 158 | |
| 155 | 159 | fn free(opt_old_base: ?[*]align(alignment_bytes) u8) callconv(.c) void { |
| 156 | 160 | const old_base = opt_old_base orelse return; |
| 157 | | const old_header: *Header = .fromBase(old_base); |
| 158 | | assert(old_header.padding == 0); |
| 161 | const old_header: Header = .get(old_base); |
| 159 | 162 | const old_size = old_header.size; |
| 160 | 163 | const old_alignment = old_header.alignment; |
| 161 | 164 | const old_alignment_bytes = old_alignment.toByteUnits(); |
| ... | ... | @@ -166,8 +169,7 @@ fn free(opt_old_base: ?[*]align(alignment_bytes) u8) callconv(.c) void { |
| 166 | 169 | |
| 167 | 170 | fn malloc_usable_size(opt_old_base: ?[*]align(alignment_bytes) u8) callconv(.c) usize { |
| 168 | 171 | const old_base = opt_old_base orelse return 0; |
| 169 | | const old_header: *Header = .fromBase(old_base); |
| 170 | | assert(old_header.padding == 0); |
| 172 | const old_header: Header = .get(old_base); |
| 171 | 173 | const old_size = old_header.size; |
| 172 | 174 | return old_size; |
| 173 | 175 | } |