Your suspicions are correct. That code returns a dangling stack pointer. I found this article does a pretty good job of explaining whats happening.
If you wanted to check your assumptions, you might write a test like this which fails
const std = @import("std");
pub const BadStruct = struct {
data: [100]u8,
slice: []u8,
};
fn make_bad_struct() BadStruct {
var data = std.mem.zeroes([100]u8);
return .{
.data = data,
.slice = data[0..4],
};
}
test {
var s = make_bad_struct();
try std.testing.expectEqual(&s.data, s.slice.ptr);
}
std.BoundedArray might be a good choice if slice will always start from 0. If not, you might just store the bounds and provide a slice() method. Maybe something like this:
Its important to notice that slice() accepts a pointer. This way we don’t return a dangling pointer, but a reference to the data stored outside of the slice() method.