authorgravatar for 35425444+leoconst@users.noreply.github.comLeo Constantinides <35425444+leoconst@users.noreply.github.com> 2023-02-12 00:04:27+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-02-12 00:04:27+00:00
logabc9530a88d24350481d9264edcde300f293929a
tree00e68ca6c61c7d467fc9e953a32324c69f5a2364
parente10c0eefde9f994deac55406f9cd099f8a1f56ed
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std: check types of pointers passed to allocator functions


2 files changed, 35 insertions(+), 8 deletions(-)

lib/std/heap/general_purpose_allocator.zig+6-2
......@@ -397,7 +397,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
397397 const prev = bucket.prev;
398398 if (config.never_unmap) {
399399 // free page that was intentionally leaked by never_unmap
400 self.backing_allocator.free(bucket.page[0..page_size]);
400 const array_ptr = bucket.page[0..page_size];
401 comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8);
402 self.backing_allocator.free(@as([]align(page_size) u8, array_ptr));
401403 }
402404 // alloc_cursor was set to slot count when bucket added to empty_buckets
403405 self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor));
......@@ -814,7 +816,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
814816 self.buckets[bucket_index] = bucket.prev;
815817 }
816818 if (!config.never_unmap) {
817 self.backing_allocator.free(bucket.page[0..page_size]);
819 const array_ptr = bucket.page[0..page_size];
820 comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8);
821 self.backing_allocator.free(@as([]align(page_size) u8, array_ptr));
818822 }
819823 if (!config.retain_metadata) {
820824 self.freeBucket(bucket, size_class);
lib/std/mem/Allocator.zig+29-6
......@@ -109,7 +109,7 @@ pub fn create(self: Allocator, comptime T: type) Error!*T {
109109/// `ptr` should be the return value of `create`, or otherwise
110110/// have the same address and alignment property.
111111pub fn destroy(self: Allocator, ptr: anytype) void {
112 const info = @typeInfo(@TypeOf(ptr)).Pointer;
112 const info = ensureSlice(@TypeOf(ptr), "destroy", .One);
113113 const T = info.child;
114114 if (@sizeOf(T) == 0) return;
115115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
......@@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr(
224224/// the pointer, however the allocator implementation may refuse the resize
225225/// request by returning `false`.
226226pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
227 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
227 const Slice = ensureSlice(@TypeOf(old_mem), "resize", .Slice);
228228 const T = Slice.child;
229229 if (new_n == 0) {
230230 self.free(old_mem);
......@@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
245245/// can be larger, smaller, or the same size as the old memory allocation.
246246/// If `new_n` is 0, this is the same as `free` and it always succeeds.
247247pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {
248 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
248 const Slice = ensureSlice(@TypeOf(old_mem), "realloc", .Slice);
249249 break :t Error![]align(Slice.alignment) Slice.child;
250250} {
251251 return self.reallocAdvanced(old_mem, new_n, @returnAddress());
......@@ -257,10 +257,10 @@ pub fn reallocAdvanced(
257257 new_n: usize,
258258 return_address: usize,
259259) t: {
260 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
260 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);
261261 break :t Error![]align(Slice.alignment) Slice.child;
262262} {
263 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
263 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);
264264 const T = Slice.child;
265265 if (old_mem.len == 0) {
266266 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);
......@@ -293,7 +293,7 @@ pub fn reallocAdvanced(
293293/// Free an array allocated with `alloc`. To free a single item,
294294/// see `destroy`.
295295pub fn free(self: Allocator, memory: anytype) void {
296 const Slice = @typeInfo(@TypeOf(memory)).Pointer;
296 const Slice = ensureSlice(@TypeOf(memory), "free", .Slice);
297297 const bytes = mem.sliceAsBytes(memory);
298298 const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
299299 if (bytes_len == 0) return;
......@@ -318,6 +318,29 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {
318318 return new_buf[0..m.len :0];
319319}
320320
321inline fn ensureSlice(
322 comptime Type: type,
323 comptime function_name: []const u8,
324 comptime expected_size: std.builtin.Type.Pointer.Size,
325) std.builtin.Type.Pointer {
326 const expectation = switch (expected_size) {
327 .One => "a single item pointer",
328 .Slice => "a slice",
329 else => unreachable,
330 };
331 const type_info = @typeInfo(Type);
332
333 if (type_info == .Pointer) {
334 const pointer = type_info.Pointer;
335
336 if (pointer.size == expected_size) {
337 return pointer;
338 }
339 }
340
341 @compileError(std.fmt.comptimePrint("{s} expects {s} but received a value of type `{s}`", .{ function_name, expectation, @typeName(Type) }));
342}
343
321344/// TODO replace callsites with `@log2` after this proposal is implemented:
322345/// https://github.com/ziglang/zig/issues/13642
323346inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {