? Can I use blabla safely later knowing that buf will not be reclaimed by stack later, in all optimize modes? I’m using first pattern quite often in Zig and just wondered if it’s actually sort of UAF, like in:
var ptr: *u32 = undefined;
{
var val: u32 = 20 * 1024;
ptr = &val;
}
(since slice is also just pointer + length) and I was just lucky to not find bug in runtime.
Currently zig does allocate all the stack variables at the beginning of a function, reserving separate regions of memory for each scope.
So with the current compiler implementation the pointer is valid until the end of the function in any release mode.
However, I wouldn’t assume that this remains true in the future. I couldn’t find a mention of this behavior in the documentation, so it’s likely just a by-product of the current implementation instead of a supported feature.
And it does look like a good optimization opportunity(especially for recursive functions) to remove the inner scope buffers at the end of their scope. So I would guess that Zig will change this in the future.
I think a good alternative would be to use a FixedBufferAllocator and a combined buffer for the entire function scope:
I have at least one small example here for 0.12.0-dev.1454+f24ceec35, where in ReleaseSmall compiler puts larger buffer to the beginning and smaller to the ~ larger + slice.len space (right after slice of beginning), so in the end it both preserved slice and used unused space from first buffer for the second (~ slice.len + smaller.len, all of them with power of 2 sizes). Judging from various IR outputs it looks like LLVM deducted that they are allowed to alias and used this fact, but IDK why it didn’t ignored slice. In other words, (at least LLVM) do use available space from the scopes in ReleaseSmall as long as it’s not used for any other purposes.
Unfortunately, with default trace length and FBA logic it produces quite unsatisfying deep errors for me (unlike easy-to-spot error about too long slicing), so I think I’ll just move buffers to the function scope instead:
var blabla_buf: [1024]u8 = undefined;
const blabla = blabla: {
// some logic here...
break :blabla blabla_buf[0..len];
};
Thank you very much for your answers! Will mark as solution now.