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);
 }