From be483dabc8fade06ad21b1e45c2bc731c4c4dd4f Mon Sep 17 00:00:00 2001 From: samy007 <samy2014@free.fr> Date: Mon, 24 Mar 2025 22:05:57 +0100 Subject: [PATCH 1/2] fix: Allocator.remap now handles zero-bytes sized types --- lib/std/mem.zig | 12 ++++++++++++ lib/std/mem/Allocator.zig | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 016f3ab9da7a..320c71f33d5b 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -228,6 +228,18 @@ test "Allocator.resize" { } } +test "Allocator alloc and remap with zero-bit type" { + var values = try testing.allocator.alloc(void, 10); + defer testing.allocator.free(values); + + try testing.expectEqual(10, values.len); + const remaped = testing.allocator.remap(values, 200); + try testing.expect(remaped != null); + + values = remaped.?; + try testing.expectEqual(200, values.len); +} + /// Copy all of source into dest at position 0. /// dest.len must be >= source.len. /// If the slices overlap, dest.ptr must be <= src.ptr. diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 1ad953311604..9995e65ad00c 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -311,12 +311,15 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool { /// `allocation` may be an empty slice, in which case a new allocation is made. /// /// `new_len` may be zero, in which case the allocation is freed. +/// +/// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`. pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: { const Slice = @typeInfo(@TypeOf(allocation)).pointer; break :t ?[]align(Slice.alignment) Slice.child; } { const Slice = @typeInfo(@TypeOf(allocation)).pointer; const T = Slice.child; + const alignment = Slice.alignment; if (new_len == 0) { self.free(allocation); @@ -325,6 +328,11 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: { if (allocation.len == 0) { return null; } + if (@sizeOf(T) == 0) { + var new_memory = allocation; + new_memory.len = new_len; + return new_memory; + } const old_memory = mem.sliceAsBytes(allocation); // I would like to use saturating multiplication here, but LLVM cannot lower it // on WebAssembly: https://github.com/ziglang/zig/issues/9660 From 4595b1ee06972df7ad913acb5349a1c5e7b07451 Mon Sep 17 00:00:00 2001 From: samy007 <samy2014@free.fr> Date: Mon, 24 Mar 2025 22:08:05 +0100 Subject: [PATCH 2/2] std.mem.bytesAsSlice: fix to support zero-bytes sized types also added a test for json parsing of zero sized type --- lib/std/json/static_test.zig | 16 ++++++++++++++++ lib/std/mem.zig | 16 +++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/std/json/static_test.zig b/lib/std/json/static_test.zig index 3375ae057216..3a1919e40c00 100644 --- a/lib/std/json/static_test.zig +++ b/lib/std/json/static_test.zig @@ -925,3 +925,19 @@ test "parse at comptime" { }; comptime testing.expectEqual(@as(u64, 9999), config.uptime) catch unreachable; } + +test "parse with zero-bit field" { + const str = + \\{ + \\ "a": ["a", "a"], + \\ "b": "a" + \\} + ; + const ZeroSizedEnum = enum { a }; + try testing.expectEqual(0, @sizeOf(ZeroSizedEnum)); + + const Inner = struct { a: []const ZeroSizedEnum, b: ZeroSizedEnum }; + const expected: Inner = .{ .a = &.{ .a, .a }, .b = .a }; + + try testAllParseFunctions(Inner, expected, str); +} diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 320c71f33d5b..2363fe125ef3 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -4219,10 +4219,11 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { /// Given a slice of bytes, returns a slice of the specified type /// backed by those bytes, preserving pointer attributes. +/// If `T` is zero-bytes sized, the returned slice has a len of zero. pub fn bytesAsSlice(comptime T: type, bytes: anytype) BytesAsSliceReturnType(T, @TypeOf(bytes)) { // let's not give an undefined pointer to @ptrCast // it may be equal to zero and fail a null check - if (bytes.len == 0) { + if (bytes.len == 0 or @sizeOf(T) == 0) { return &[0]T{}; } @@ -4300,6 +4301,19 @@ test "bytesAsSlice preserves pointer attributes" { try testing.expectEqual(in.alignment, out.alignment); } +test "bytesAsSlice with zero-bit element type" { + { + const bytes = [_]u8{}; + const slice = bytesAsSlice(void, &bytes); + try testing.expectEqual(0, slice.len); + } + { + const bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + const slice = bytesAsSlice(u0, &bytes); + try testing.expectEqual(0, slice.len); + } +} + fn SliceAsBytesReturnType(comptime Slice: type) type { return CopyPtrAttrs(Slice, .slice, u8); }