Am Sonntag, dem 08.12.2024 um 11:26 +0000 schrieb David Laight: > From: Martin Uecker > > Sent: 07 December 2024 23:52 > ... > > While the compiler can not automatically prove every use > > of VLA bounded, it can reliably diagnose the cases where it > > can *not* see that it is bounded. Consider this example: > > > > void oob(int n, char p[n]); > > void f(unsigned int n) > > { > > char buf[MIN(n, 100)]; // bounded > > oob(n + 10, buf); // warning > > } > ... > > The kernel stack has to have enough space for the [100] > so the full amount might as well always be allocated. > The chance of 'trading off' stack usage with another function > in the same call stack that is guaranteed to use less than > its maximum is about zero. In numerical computing this is a big motivation because you can reduce stack usage in recursive divide-and-conquer algorithms. For the kernel, I agree this is not a compelling use case, and the better motivation would be precise bounds checking and clearer semantics for buffer management. But don't get me wrong, if the kernel is happier without VLA this is fine with me, I am just trying to understand the underlying issues better and the "VLAs are security problem" or "VLA use more stack" arguments do not convince me, while the points Linus raises make much more sense to me. > > The VLA code also adds an extra stack frame, this pretty much > pessimises everything. Yes, but this is something which seems could be improved on the compiler side, e.g. by simply transforming small VLAs automatically to a fixed size array while preserving their semantics for bound checking. > This happened for 'constant' sizes from min(16, sizeof (struct)) > because min() needs to be a statement function to avoid re-evaluating > its arguments. Can you clarify this? If the VLA size is constant, even when it is not an integer constant expression according to ISO C, the compiler should not produce worse code. For example, void g(void*); void foo() { int n = 10; char buf[n]; g(buf); } void bar() { char buf[10]; g(buf); } So a lot of this macro business seems to be necessary to avoid creating warnings for ISO VLAs when instead you really care about the created code not having a dynamic allocation on the stack. So one might wonder whether a compiler warning that warns more specifically about this would help. > (The version of min() that managed to return constant from constant > input just exploded in cpp, partially responsible for 18MB lines > being fed into the compiler part.) The issue here is that we miss a language feature in C to introduce local variables that help avoid multiple expansion of macro arguments. GCC's statement expressions and __auto_type are a solution #define foo(x) ({ __auto_type __x = (x); ... }) but this runs into the current limitations that ({ }) can not be used at file-scope and can not return constant expressions. For other reasons I was thinking about adding names to _Generic, as in _Generic(x, int i: (i + 1)); because one design issues with _Generic is that it typechecks also the untaken associations and there the 'x' then has the wrong type. Having an 'i' with the right type which is set to the value of 'x' when the branch is taken would fix this issue. But this feature might also allow writing macros that avoid doublel expansion without requiring statement expressions (which are more difficult to fix): #define foo(x) _Generic(x, int i: (i + i)); Martin