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