Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor fix for Allocator.remap and mem.bytesAsSlice for zero-sized types #23220

Merged
merged 2 commits into from
Mar 25, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/std/json/static_test.zig
Original file line number Diff line number Diff line change
@@ -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);
}
28 changes: 27 additions & 1 deletion lib/std/mem.zig
Original file line number Diff line number Diff line change
@@ -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.
@@ -4207,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{};
}

@@ -4288,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);
}
8 changes: 8 additions & 0 deletions lib/std/mem/Allocator.zig
Original file line number Diff line number Diff line change
@@ -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