Hi Paul,

On Sun, Dec 14, 2025 at 02:00:05PM -0800, Paul Eggert wrote:
> On 2025-12-14 13:18, Alejandro Colomar wrote:
> 
> > In GNU C, [n] means you can
> > access the first n elements.
> 
> Oh, I didn't know that. Where is this documented? I looked in the GCC manual
> but couldn't find it.

There's <https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html>, but
it doesn't say much.  It's essentially an undocumented feature.

> Also, how can one tell that GNU C supports this extension? Is there a sample
> program illustrating the support?

Yup, here's one:

        alx@devuan:~/tmp$ cat ap.c 
        void g(int a[43]);

        void f(int a[42]);
        void f(int a[42])
        {
                a[101] = 8;
                g(a);
        }

        void h(void);
        void h(void)
        {
                int a[7];
                int b[77];

                g(a);
                g(b);
        }
        alx@devuan:~/tmp$ gcc -Wall -Wextra -S -O2 ap.c 
        ap.c: In function ‘f’:
        ap.c:7:9: warning: ‘g’ accessing 172 bytes in a region of size 168 
[-Wstringop-overflow=]
            7 |         g(a);
              |         ^~~~
        ap.c:7:9: note: referencing argument 1 of type ‘int[43]’
        ap.c:1:6: note: in a call to function ‘g’
            1 | void g(int a[43]);
              |      ^
        ap.c: In function ‘h’:
        ap.c:16:9: warning: ‘g’ accessing 172 bytes in a region of size 28 
[-Wstringop-overflow=]
           16 |         g(a);
              |         ^~~~
        ap.c:16:9: note: referencing argument 1 of type ‘int[43]’
        ap.c:1:6: note: in a call to function ‘g’
            1 | void g(int a[43]);
              |      ^
        ap.c: In function ‘f’:
        ap.c:6:10: warning: array subscript 101 is outside array bounds of 
‘int[42]’ [-Warray-bounds=]
            6 |         a[101] = 8;
              |         ~^~~~~
        ap.c:4:12: note: at offset 404 into object ‘a’ of size [0, 168]
            4 | void f(int a[42])
              |        ~~~~^~~~~

> Which versions of GCC support the
> extension?

You could check the history in the git-log(1) and in bugzilla.  The
diagnostic flags you want to look for are -Warray-bounds,
-Warray-parameter, and -Wstringop-overflow.  Support has been growing
over time.  GCC 15 had some significant improvements, but there was some
support before that.  Also, there's still some false negatives, so it
will keep improving in the future.

You may also ask Martin Uecker; he has contributed to that code
recently.

> > At least, I'd suggest that gnulib uses [n] in GCC, and leaves [static n]
> > for those crappy dialects where [n] means nothing.
> 
> Well, as present Gnulib code is not using this GCC extension and as far as I
> can see it is unlikely to use the extension, at least not until many years
> after it's standardized, as it's too much of a pain to use the extension in
> code meant to be portable to non-GNU compilers.

The code is simply ignored in non-GNU compilers.  You won't get quality
diagnostics from them, but you won't get bad semantics either.

Also, compilers have largely ignored [static n] historically.  The only
ones that implement it are Clang and GCC, AFAIK.  And Clang is quite
limited in what it diagnoses.  It's mainly used as a UB bomb ^W^W
optimization tool.

The support for [static n] ain't significantly better than the support
for [n].

> > The problem is that static checking of null pointers is incomplete, or
> > so I remember.  It's been a long time since I last checked that.
> 
> Of course one cannot do a "perfect" job of static checking - that's
> equivalent to solving the halting problem.

The _Optional qualifier proposed in
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3422.pdf> promises to
be able to do an almost perfect job.  I need to try it in a mature
project.  There's a patch set for implementing it in Clang which I'll
use to test how well it works.

> But that's OK, the static
> checking suffices for practical code. Plus, the dynamic checking in
> functions like execl is needed only for broken callers - as far as I know
> it's present only for compatibility with mistakes made back in the 1970s
> (back when null pointers could be dereferenced! the good old days...).
> 
> 
> > You still get static checking with [[gnu::nonnull()]] and
> > -fno-delete-null-pointer-checks.  I don't use
> > -fno-delete-null-pointer-checks to remove dynamic checks, but to not
> > allow the compiler to abuse UB in the few cases where the compiler is
> > unable to diagnose.
> 
> Those two things are the same thing, right? I'm not quite following.

The problem is not that it allows removing things like

        assert(p != NULL);

inside a function.  The problem is that UB propagates backwards, so that
you can observe it even before it has been triggered.  The compiler
might think "hey, since we're getting a null here, and it's impossible,
maybe the whole path that led to here is also impossible, ...", turning
a program into something completely different.  An invocation of the
program might not even call the function that had the UB, but because
the program contains UB, it affects the entire program.


Cheers,
Alex

> But anyway, this is low priority as we need not cater to unportable apps
> that pass null pointers to the likes of execl.

-- 
<https://www.alejandro-colomar.es>

Attachment: signature.asc
Description: PGP signature

Reply via email to