Am Freitag, dem 23.08.2024 um 15:46 +1200 schrieb Michael Clark via Gcc: > On 8/23/24 15:24, Michael Clark wrote: > > On 8/15/24 06:24, Michael Clark wrote: > > > Hi Folks, > > > > > like I said this is crazy talk as alloca isn't even in the C standard. > > but VLAs are, and the current implementation of VLAs depends on alloca. > > one more thing. it doesn't require PT_GNU_STACK or writable stacks like > GCC nested functions. :-) so I think it is safer but it does have safety > issues, mostly related to stack overflows but its going to need some > careful analysis with respect to ROP. returning deduced VLA types with > bounds references in frame metadata and a chain of frame pointers for > dynamic alloca might help. also my experiment in LLVM needs clobbers in > the parent frame because while I was able to modify the epilogue based > on an attribute, I so far haven't figured out how to make it look to the > translator like an alloca in the parent frame so that subsequent > references to earlier locals save their stack pointer in a register. > > this was my first test function: > > char* f(int n) __attribute__((allocareturn)) > { > static const char* fmt = "num-%d"; > int len = snprintf(0, 0, fmt, n); > char *str = __builtin_alloca(len+1); > snprintf(str, len+1, fmt, n); > return str; > } > > but this also works: > > char* f(int n) __attribute__((allocareturn)) > { > static const char* fmt = "num-%d"; > int len = snprintf(0, 0, fmt, n); > char str[len+1]; > snprintf(str, len+1, fmt, n); > return str; > } > > and this is even better: > > f(int n) -> auto > { > static const char* fmt = "num-%d"; > int len = snprintf(0, 0, fmt, n); > char str[len+1]; > snprintf(str, len+1, fmt, n); > return str; > } > > like a reference in an implicit copy constructor for a structure. > > struct anon123456 { int &n; int arr[n]; }; > > that would be positioned at the end of the fixed frame so that the > parent function knows where the bound is. like I said. crazy talk.
In your example, the length would already be known to the caller. In this case, this should be easier. Or do you also want this to work for when the length is computed inside the callee? If you return a structure, this would typically (always) returned in a memory region allocated by the caller. So for a known constant size you can allocate on the caller stack already: struct foo { char buf[128]; } f(); In GCC this also works for dynamic size, when you put a VLA inside the struct struct foo { char buf[n]; } f(); but this is only allowed as a nested function. https://godbolt.org/z/YTY6MMf15 But in principle, this works already. I we syntactically allowed auto f(int n) -> struct foo { char buf[n]; }; then this should work also at file scope for a caller supplied size. If the size needs to be computed in the callee then this is much harder. Martin > > Michael.