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 {...@@ -397,7 +397,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
397 const prev = bucket.prev;397 const prev = bucket.prev;
398 if (config.never_unmap) {398 if (config.never_unmap) {
399 // free page that was intentionally leaked by never_unmap399 // 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));
401 }403 }
402 // alloc_cursor was set to slot count when bucket added to empty_buckets404 // alloc_cursor was set to slot count when bucket added to empty_buckets
403 self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor));405 self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor));
...@@ -814,7 +816,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -814,7 +816,9 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
814 self.buckets[bucket_index] = bucket.prev;816 self.buckets[bucket_index] = bucket.prev;
815 }817 }
816 if (!config.never_unmap) {818 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));
818 }822 }
819 if (!config.retain_metadata) {823 if (!config.retain_metadata) {
820 self.freeBucket(bucket, size_class);824 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 {...@@ -109,7 +109,7 @@ pub fn create(self: Allocator, comptime T: type) Error!*T {
109/// `ptr` should be the return value of `create`, or otherwise109/// `ptr` should be the return value of `create`, or otherwise
110/// have the same address and alignment property.110/// have the same address and alignment property.
111pub fn destroy(self: Allocator, ptr: anytype) void {111pub fn destroy(self: Allocator, ptr: anytype) void {
112 const info = @typeInfo(@TypeOf(ptr)).Pointer;112 const info = ensureSlice(@TypeOf(ptr), "destroy", .One);
113 const T = info.child;113 const T = info.child;
114 if (@sizeOf(T) == 0) return;114 if (@sizeOf(T) == 0) return;
115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
...@@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr(...@@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr(
224/// the pointer, however the allocator implementation may refuse the resize224/// the pointer, however the allocator implementation may refuse the resize
225/// request by returning `false`.225/// request by returning `false`.
226pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {226pub 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);
228 const T = Slice.child;228 const T = Slice.child;
229 if (new_n == 0) {229 if (new_n == 0) {
230 self.free(old_mem);230 self.free(old_mem);
...@@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {...@@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
245/// can be larger, smaller, or the same size as the old memory allocation.245/// can be larger, smaller, or the same size as the old memory allocation.
246/// If `new_n` is 0, this is the same as `free` and it always succeeds.246/// If `new_n` is 0, this is the same as `free` and it always succeeds.
247pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {247pub 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);
249 break :t Error![]align(Slice.alignment) Slice.child;249 break :t Error![]align(Slice.alignment) Slice.child;
250} {250} {
251 return self.reallocAdvanced(old_mem, new_n, @returnAddress());251 return self.reallocAdvanced(old_mem, new_n, @returnAddress());
...@@ -257,10 +257,10 @@ pub fn reallocAdvanced(...@@ -257,10 +257,10 @@ pub fn reallocAdvanced(
257 new_n: usize,257 new_n: usize,
258 return_address: usize,258 return_address: usize,
259) t: {259) t: {
260 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;260 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);
261 break :t Error![]align(Slice.alignment) Slice.child;261 break :t Error![]align(Slice.alignment) Slice.child;
262} {262} {
263 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;263 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);
264 const T = Slice.child;264 const T = Slice.child;
265 if (old_mem.len == 0) {265 if (old_mem.len == 0) {
266 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);266 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);
...@@ -293,7 +293,7 @@ pub fn reallocAdvanced(...@@ -293,7 +293,7 @@ pub fn reallocAdvanced(
293/// Free an array allocated with `alloc`. To free a single item,293/// Free an array allocated with `alloc`. To free a single item,
294/// see `destroy`.294/// see `destroy`.
295pub fn free(self: Allocator, memory: anytype) void {295pub fn free(self: Allocator, memory: anytype) void {
296 const Slice = @typeInfo(@TypeOf(memory)).Pointer;296 const Slice = ensureSlice(@TypeOf(memory), "free", .Slice);
297 const bytes = mem.sliceAsBytes(memory);297 const bytes = mem.sliceAsBytes(memory);
298 const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;298 const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
299 if (bytes_len == 0) return;299 if (bytes_len == 0) return;
...@@ -318,6 +318,29 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {...@@ -318,6 +318,29 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {
318 return new_buf[0..m.len :0];318 return new_buf[0..m.len :0];
319}319}
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
321/// TODO replace callsites with `@log2` after this proposal is implemented:344/// TODO replace callsites with `@log2` after this proposal is implemented:
322/// https://github.com/ziglang/zig/issues/13642345/// https://github.com/ziglang/zig/issues/13642
323inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {346inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {