Am Montag, dem 04.12.2023 um 13:27 -0500 schrieb Siddhesh Poyarekar:
> [Branching this into a separate conversation to avoid derailing the
> patch, which isn't directly related]
>
> On 2023-12-04 12:21, Martin Uecker wrote:
> > I do not really agree with that. Nested functions can substantially
> > improve code quality and in C can avoid type unsafe use of
> > void* pointers in callbacks. The code is often much better with
> > nested functions than without. Nested functions and lambdas
> > (i.e. anonymous nested functions) are used in many languages
> > because they make code better and GNU's nested function are no
> > exception.
> >
> > So I disagree with the idea that discouraging nested functions leads
> > to better code - I think the exact opposite is true.
>
> I would argue that GNU's nested functions *are* an exception because
> they're like feathers stuck on a pig to try and make it fly; I think a
> significant specification effort is required to actually make it a
> cleanly usable feature. It *may* be possible to implement patterns that
> use C nested functions well enough *and* result in readable code, but
> IMO it is easier to write clunky and unmaintainable code with it.
I use them in my code a lot and I think they improve
code quality. For example:
int foo_find(int N, struct foo in_array[N], const char* *key)
{
bool cond(struct foo* x)
{
return 0 == strcmp(x->name, key);
}
return find(N, in_array, cond);
}
is a lot cleaner and safer than what you need to write
without nested functions:
struct foo_find {
const char* name;
};
int foo_cond(void *vdata, struct foo* a)
{
struct foo *key = data;
return 0 == strcmp(x->name, key->name);
}
void foo_sort(int N, struct foo in_array[N], const char* key)
{
struct foo_find data = { key };
sort(N, in_array, foo_cond, &data);
}
and this is a toy example, the improvement gets more
substantial with more complicated logic.
>
> I empathize with Jakub's stated use case though of keeping the C
> frontend support for testing purposes, but that could easily be done
> behind a flag, or by putting nested C func deprecation behind a flag.
I am relatively sure C will get some form of nested functions.
Maybe as anonymous nested functions, i.e. lambdas, but I do
not see a fundamental difference here (I personally like naming
things for clarity, so i prefer named nested functions)
> > I am generally wary of mitigations that may make exploitation of
> > buffer overflows a bit harder while increasing the likelihood
> > of buffer overflows by reducing type safety and/or code quality.
> >
> > But I would agree that trampolines are generally problematic. A
> > better strategy would be wide function pointer type (as in Apple'
> > Blocks extension). Alternatively, an explicit way to obtain the
> > static chain for a nested function which could be used with
> > __builtin_call_with_static_chain could also work.
> >
> > But in any case, I think it diminishes the value of -fhardening
> > it if requires source code changes, because then it is not as easy
> > to simply turn it on in larger projects / distributitions.
>
> I suppose you mean source code changes even in correct code just to
> comply with the flag?
Yes
> I don't disagree for cases like -Warray-bounds,
> but for warnings/errors that are more deterministic in nature (like
> -Werror=trampolines), they're going to point at actual problems and
> larger projects and distributions will usually prefer to at least track
> them, if not actually fix them. For Fedora we tend to provide macro
> overrides for packages that need to explicitly disable a security
> related flag.
In projects such as mine, this will lead to a lot of code
transformations as indicated above, i.e. much worse code.
One could get away with it, since nested functions are rarely
used, but I think this is bad, because a lot of code would
improve if it used them.
Martin
>
> Thanks,
> Sid