ziglang / zig

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

const pointer to empty nul-terminated array doesn't cast to slice #13874

Open nektro opened 1 year ago

nektro commented 1 year ago

Zig Version

0.11.0-dev.661+d88eb75a6

Steps to Reproduce and Observed Behavior

pub fn main() void {
    _ = foo();
}

fn foo() [:0]u8 {
    return &[_:0]u8{};
}
/home/meghan/src/zig/test.zig:6:12: error: expected type '[:0]u8', found '*const [0:0]u8'
    return &[_:0]u8{};
           ^~~~~~~~~~
/home/meghan/src/zig/test.zig:6:12: note: cast discards const qualifier
/home/meghan/src/zig/test.zig:5:10: note: function return type declared here
fn foo() [:0]u8 {
         ^~~~~~

Expected Behavior

pass the same way it does for []u8

InKryption commented 1 year ago

Wouldn't that require that memory be allocated for the sentinel though?

nektro commented 1 year ago

no because making the array its own variable also works and so does inline for non-sentinel

pub fn main() void {
    _ = foo();
}

fn foo() [:0]u8 {
    var arr = [_:0]u8{};
    return &arr;
}

this also runs without error

InKryption commented 1 year ago

That just looks like you're returning a pointer to stack memory. This works:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    var a = "foo".*;
    const b: [:0]u8 = a[0..];
    b[b.len] = 3;
    print("{any}\n", .{b[b.len]});
}

because the sentinel is also part of the mutable memory.

mlugg commented 1 year ago

The reason this coercion is valid for non-sentinel arrays is because they're 0 bytes long - as InKryption says, that's not the case here due to the sentinel value. The var one clearly works (well, compiles) because you're marking the array var so the pointer isn't const to begin with.

nektro commented 1 year ago

its technically a pointer to stack memory but the slice has a length of 0 so it should remain valid

InKryption commented 1 year ago

Even when it has a length of 0, the sentinel is still there, and still requires memory. The true size of a sentinel-terminated X is always @sizeOf(T) * (len + 1). So your slice there is actually not truly empty, it just doesn't have any non-sentinel elements.

nektro commented 1 year ago

even still, the sentinel in this case should be able to be put in the readonly data part of an executable. &[_:0]u8{} is semantically the same thing as ""

InKryption commented 1 year ago

It can't be in read-only data, because you can still modify the sentinel:

test {
    var a = "".*;
    a[0] = 42;
}
nektro commented 1 year ago

because the sentinel is also part of the mutable memory.

sorry, missed that part from your earlier comment. wait what? that should definitely be safety checked imo

AssortedFantasy commented 1 year ago

Addresses of temporaries are now const. https://ziglang.org/download/0.10.0/release-notes.html#Address-of-Temporaries-Now-Produces-Const-Pointers

Your code is trying to make a non const slice which won't cast from a pointer to const.

mlugg commented 1 year ago

Your code is trying to make a non const slice which won't cast from a pointer to const.

They know this; the confusion is coming from sentinel arrays specifically. The expression &.{} is actually allowed to coerce to a mutable slice (since it doesn't refer to any memory so it's safe to "mutate" any of its 0 elements), and the confusion here is coming from the fact that this doesn't apply to sentinel-terminated arrays (due to the sentinel itself being stored).

nektro commented 6 months ago

to add clarification, the thesis of this issue is that the bug is "because the sentinel is also part of the mutable memory" and attempting to write at the sentinels position should instead be Illegal Behavior.

writing over the sentinel should require [:S]T to be casted to a []T with slice.len + 1 or a [*]T.

making this change would allow a zero-length sentineled slice to be stored in constant memory.

Pyrolistical commented 6 months ago

Additional discord discussion: https://discord.com/channels/605571803288698900/906306963942543370/1228084517059690628