| author | |
| committer | |
| log | 36e9b0f0261a5421f22dbf17f513a8c2f685c5d3 |
| tree | 62e7d47f13e388f4db799b597a7617b80c2d9d48 |
| parent | 2c5113f6d1ee9d5041d9d79cfbe13e6bea2aff56 |
Reversal on the decision: the Allocator interface is the correct place
for the memset to undefined because it allows Allocator implementations
to bypass the interface and use a backing allocator directly, skipping
the performance penalty of memsetting the entire allocation, which may
be very large, as well as having valuable zeroes on them.
closes #42982 files changed, 27 insertions(+), 19 deletions(-)
lib/std/heap/general_purpose_allocator.zig+23-12| ... | @@ -157,6 +157,9 @@ pub const Config = struct { | ... | @@ -157,6 +157,9 @@ pub const Config = struct { |
| 157 | 157 | ||
| 158 | /// Enables emitting info messages with the size and address of every allocation. | 158 | /// Enables emitting info messages with the size and address of every allocation. |
| 159 | verbose_log: bool = false, | 159 | verbose_log: bool = false, |
| 160 | |||
| 161 | /// Tell whether the backing allocator returns already-zeroed memory. | ||
| 162 | backing_allocator_zeroes: bool = true, | ||
| 160 | }; | 163 | }; |
| 161 | 164 | ||
| 162 | pub const Check = enum { ok, leak }; | 165 | pub const Check = enum { ok, leak }; |
| ... | @@ -179,7 +182,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -179,7 +182,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 179 | 182 | ||
| 180 | const Self = @This(); | 183 | const Self = @This(); |
| 181 | 184 | ||
| 182 | /// The initial state of a `GeneralPurposeAllocator`, containing no allocations and backed by the system page allocator. | 185 | /// The initial state of a `GeneralPurposeAllocator`, containing no |
| 186 | /// allocations and backed by the system page allocator. | ||
| 183 | pub const init: Self = .{ | 187 | pub const init: Self = .{ |
| 184 | .backing_allocator = std.heap.page_allocator, | 188 | .backing_allocator = std.heap.page_allocator, |
| 185 | .buckets = [1]Buckets{.{}} ** small_bucket_count, | 189 | .buckets = [1]Buckets{.{}} ** small_bucket_count, |
| ... | @@ -508,7 +512,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -508,7 +512,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 508 | fn collectStackTrace(first_trace_addr: usize, addresses: *[stack_n]usize) void { | 512 | fn collectStackTrace(first_trace_addr: usize, addresses: *[stack_n]usize) void { |
| 509 | if (stack_n == 0) return; | 513 | if (stack_n == 0) return; |
| 510 | @memset(addresses, 0); | 514 | @memset(addresses, 0); |
| 511 | var stack_trace = StackTrace{ | 515 | var stack_trace: StackTrace = .{ |
| 512 | .instruction_addresses = addresses, | 516 | .instruction_addresses = addresses, |
| 513 | .index = 0, | 517 | .index = 0, |
| 514 | }; | 518 | }; |
| ... | @@ -1092,22 +1096,29 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -1092,22 +1096,29 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 1092 | } | 1096 | } |
| 1093 | 1097 | ||
| 1094 | fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader { | 1098 | fn createBucket(self: *Self, size_class: usize) Error!*BucketHeader { |
| 1095 | const page = try self.backing_allocator.alignedAlloc(u8, page_size, page_size); | 1099 | const alignment: mem.Alignment = .fromByteUnits(page_size); |
| 1096 | errdefer self.backing_allocator.free(page); | 1100 | const page = self.backing_allocator.rawAlloc(page_size, alignment, @returnAddress()) orelse |
| 1101 | return error.OutOfMemory; | ||
| 1102 | errdefer self.backing_allocator.rawFree(page[0..page_size], alignment, @returnAddress()); | ||
| 1097 | 1103 | ||
| 1098 | const bucket_size = bucketSize(size_class); | 1104 | const bucket_size = bucketSize(size_class); |
| 1099 | const bucket_bytes = try self.backing_allocator.alignedAlloc(u8, @alignOf(BucketHeader), bucket_size); | 1105 | const header_align: mem.Alignment = .fromByteUnits(@alignOf(BucketHeader)); |
| 1100 | const ptr: *BucketHeader = @ptrCast(bucket_bytes.ptr); | 1106 | const ptr: *BucketHeader = @alignCast(@ptrCast(self.backing_allocator.rawAlloc( |
| 1107 | bucket_size, | ||
| 1108 | header_align, | ||
| 1109 | @returnAddress(), | ||
| 1110 | ) orelse return error.OutOfMemory)); | ||
| 1101 | ptr.* = .{ | 1111 | ptr.* = .{ |
| 1102 | .page = page.ptr, | 1112 | .page = @alignCast(page), |
| 1103 | .alloc_cursor = 0, | 1113 | .alloc_cursor = 0, |
| 1104 | .used_count = 0, | 1114 | .used_count = 0, |
| 1105 | }; | 1115 | }; |
| 1106 | // Set the used bits to all zeroes | 1116 | if (!config.backing_allocator_zeroes) { |
| 1107 | @memset(@as([*]u8, @as(*[1]u8, ptr.usedBits(0)))[0..usedBitsCount(size_class)], 0); | 1117 | @memset(@as([*]u8, @as(*[1]u8, ptr.usedBits(0)))[0..usedBitsCount(size_class)], 0); |
| 1108 | if (config.safety) { | 1118 | if (config.safety) { |
| 1109 | // Set the requested sizes to zeroes | 1119 | // Set the requested sizes to zeroes |
| 1110 | @memset(mem.sliceAsBytes(ptr.requestedSizes(size_class)), 0); | 1120 | @memset(mem.sliceAsBytes(ptr.requestedSizes(size_class)), 0); |
| 1121 | } | ||
| 1111 | } | 1122 | } |
| 1112 | return ptr; | 1123 | return ptr; |
| 1113 | } | 1124 | } |
lib/std/mem/Allocator.zig+4-7| ... | @@ -128,25 +128,25 @@ pub fn noFree( | ... | @@ -128,25 +128,25 @@ pub fn noFree( |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | /// This function is not intended to be called except from within the | 130 | /// This function is not intended to be called except from within the |
| 131 | /// implementation of an Allocator | 131 | /// implementation of an `Allocator`. |
| 132 | pub inline fn rawAlloc(a: Allocator, len: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 { | 132 | pub inline fn rawAlloc(a: Allocator, len: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 { |
| 133 | return a.vtable.alloc(a.ptr, len, alignment, ret_addr); | 133 | return a.vtable.alloc(a.ptr, len, alignment, ret_addr); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | /// This function is not intended to be called except from within the | 136 | /// This function is not intended to be called except from within the |
| 137 | /// implementation of an Allocator. | 137 | /// implementation of an `Allocator`. |
| 138 | pub inline fn rawResize(a: Allocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) bool { | 138 | pub inline fn rawResize(a: Allocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) bool { |
| 139 | return a.vtable.resize(a.ptr, memory, alignment, new_len, ret_addr); | 139 | return a.vtable.resize(a.ptr, memory, alignment, new_len, ret_addr); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | /// This function is not intended to be called except from within the | 142 | /// This function is not intended to be called except from within the |
| 143 | /// implementation of an Allocator. | 143 | /// implementation of an `Allocator`. |
| 144 | pub inline fn rawRemap(a: Allocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { | 144 | pub inline fn rawRemap(a: Allocator, memory: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { |
| 145 | return a.vtable.remap(a.ptr, memory, alignment, new_len, ret_addr); | 145 | return a.vtable.remap(a.ptr, memory, alignment, new_len, ret_addr); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | /// This function is not intended to be called except from within the | 148 | /// This function is not intended to be called except from within the |
| 149 | /// implementation of an Allocator | 149 | /// implementation of an `Allocator`. |
| 150 | pub inline fn rawFree(a: Allocator, memory: []u8, alignment: Alignment, ret_addr: usize) void { | 150 | pub inline fn rawFree(a: Allocator, memory: []u8, alignment: Alignment, ret_addr: usize) void { |
| 151 | return a.vtable.free(a.ptr, memory, alignment, ret_addr); | 151 | return a.vtable.free(a.ptr, memory, alignment, ret_addr); |
| 152 | } | 152 | } |
| ... | @@ -271,7 +271,6 @@ fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count: | ... | @@ -271,7 +271,6 @@ fn allocBytesWithAlignment(self: Allocator, comptime alignment: u29, byte_count: |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | const byte_ptr = self.rawAlloc(byte_count, .fromByteUnits(alignment), return_address) orelse return Error.OutOfMemory; | 273 | const byte_ptr = self.rawAlloc(byte_count, .fromByteUnits(alignment), return_address) orelse return Error.OutOfMemory; |
| 274 | // TODO: https://github.com/ziglang/zig/issues/4298 | ||
| 275 | @memset(byte_ptr[0..byte_count], undefined); | 274 | @memset(byte_ptr[0..byte_count], undefined); |
| 276 | return @alignCast(byte_ptr); | 275 | return @alignCast(byte_ptr); |
| 277 | } | 276 | } |
| ... | @@ -391,7 +390,6 @@ pub fn reallocAdvanced( | ... | @@ -391,7 +390,6 @@ pub fn reallocAdvanced( |
| 391 | return error.OutOfMemory; | 390 | return error.OutOfMemory; |
| 392 | const copy_len = @min(byte_count, old_byte_slice.len); | 391 | const copy_len = @min(byte_count, old_byte_slice.len); |
| 393 | @memcpy(new_mem[0..copy_len], old_byte_slice[0..copy_len]); | 392 | @memcpy(new_mem[0..copy_len], old_byte_slice[0..copy_len]); |
| 394 | // TODO https://github.com/ziglang/zig/issues/4298 | ||
| 395 | @memset(old_byte_slice, undefined); | 393 | @memset(old_byte_slice, undefined); |
| 396 | self.rawFree(old_byte_slice, .fromByteUnits(Slice.alignment), return_address); | 394 | self.rawFree(old_byte_slice, .fromByteUnits(Slice.alignment), return_address); |
| 397 | 395 | ||
| ... | @@ -408,7 +406,6 @@ pub fn free(self: Allocator, memory: anytype) void { | ... | @@ -408,7 +406,6 @@ pub fn free(self: Allocator, memory: anytype) void { |
| 408 | const bytes_len = bytes.len + if (Slice.sentinel() != null) @sizeOf(Slice.child) else 0; | 406 | const bytes_len = bytes.len + if (Slice.sentinel() != null) @sizeOf(Slice.child) else 0; |
| 409 | if (bytes_len == 0) return; | 407 | if (bytes_len == 0) return; |
| 410 | const non_const_ptr = @constCast(bytes.ptr); | 408 | const non_const_ptr = @constCast(bytes.ptr); |
| 411 | // TODO: https://github.com/ziglang/zig/issues/4298 | ||
| 412 | @memset(non_const_ptr[0..bytes_len], undefined); | 409 | @memset(non_const_ptr[0..bytes_len], undefined); |
| 413 | self.rawFree(non_const_ptr[0..bytes_len], .fromByteUnits(Slice.alignment), @returnAddress()); | 410 | self.rawFree(non_const_ptr[0..bytes_len], .fromByteUnits(Slice.alignment), @returnAddress()); |
| 414 | } | 411 | } |