[PATCH 02/10] compiler.h: add is_const() as a replacement of __is_constexpr()
Martin Uecker
muecker at gwdg.de
Sun Dec 8 04:38:10 PST 2024
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
More information about the linux-arm-kernel
mailing list