ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
35.07k stars 2.56k forks source link

`std.mem.alignInSlice` does not properly handle empty slice arguments #22044

Open SnootierMoon opened 21 hours ago

SnootierMoon commented 21 hours ago

Zig Version

0.14.0-dev.2271+f845fa04a

Steps to Reproduce and Observed Behavior

The following test fails

const std = @import("std");

test {
    var b: []u8 = undefined;
    b.ptr = @ptrFromInt(20);
    b.len = 0;

    const r = std.mem.alignInSlice(b, 4);
    try std.testing.expect(r != null and r.?.len == 0);
}

because r is null.

IIUC this happens because std.mem.alignInSlice calls std.mem.sliceAsBytes, which replaces empty slices with &[0]u8{}.

Expected Behavior

I would expect either std.mem.alignInSlice to support passing in empty slices, or for there to be a doc comment about this. I think that if an empty slice with a pointer that is aligned to the boundary is passed in, then an empty slice should be returned. Note that in the example above, if b.ptr == @ptrFromInt(19) and b.len == 1, then an empty slice is returned. However, I'm not sure I fully understand how Zig wants to treat the .ptr of a slice when .len == 0, so maybe the status quo is OK: I would appreciate if someone could shed some light on this. To me, it also seems like a potential issue/footgun that sliceAsBytes can return a slice that's not at the same location as the input slice if the input slice is empty, but again maybe this is OK. At the very least, std.mem.alignInSlice should have a doc comment about passing in empty slices, because the current behavior is confusing and can lead to bugs in code that might naively use the function.