Am Freitag, dem 05.07.2024 um 16:37 +0200 schrieb Alejandro Colomar via Gcc:
> [CC += linux-man@, since we're discussing an API documented there, and
> the manual page would also need to be updated]
>
> Hi Xi, Jakub,
>
> On Fri, Jul 05, 2024 at 09:38:21PM GMT, Xi Ruoyao wrote:
> > On Fri, 2024-07-05 at 15:03 +0200, Alejandro Colomar wrote:
> > > ISO C specifies these APIs as accepting a restricted pointer in their
> > > first parameter:
> > >
> > > $ stdc c99 strtol
> > > long int strtol(const char *restrict nptr, char **restrict endptr, int
> > > base);
> > > $ stdc c11 strtol
> > > long int strtol(const char *restrict nptr, char **restrict endptr, int
> > > base);
> > >
> > > However, it should be considered a defect in ISO C. It's common to see
> > > code that aliases it:
> > >
> > > char str[] = "10 20";
> > >
> > > p = str;
> > > a = strtol(p, &p, 0); // Let's ignore error handling for
> > > b = strtol(p, &p, 0); // simplicity.
> >
> > Why this is wrong?
> >
> > During the execution of strtol() the only expression accessing the
> > object "p" is *endptr. When the body of strtol() refers "nptr" it
> > accesses a different object, not "p".
>
> <http://port70.net/~nsz/c/c11/n1570.html#6.7.3p8>
>
> Theoretically, 'restrict' is defined in terms of accesses, not just
> references, so it's fine for strtol(3) to hold two references of p in
> restrict pointers. That is, the following code is valid:
>
> int
> dumb(int *restrict a, int *restrict also_a)
> {
> // We don't access the objects
> return a == also_a;
> }
>
> int
> main(void)
> {
> int x = 3;
>
> return dumb(&x, &x);
> }
>
> However, in practice that's dumb. The caller cannot know that the
> function doesn't access the object, so it must be cautious and enable
> -Wrestrict, which should be paranoid and do not allow passing references
> to the same object in different arguments, just in case the function
> decides to access to objects. Of course, GCC reports a diagnostic for
> the previous code:
>
> $ cc -Wall -Wextra dumb.c
> dumb.c: In function ‘main’:
> dumb.c:13:21: warning: passing argument 1 to ‘restrict’-qualified
> parameter aliases with argument 2 [-Wrestrict]
> 13 | return dumb(&x, &x);
> | ^~ ~~
>
> ... even when there's no UB, since the object is not being accessed.
>
> But when the thing gets non-trivial, as in strtol(3), GCC misses the
> -Wrestrict diagnostic, as reported in
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112833>.
>
> Let's write a reproducer by altering the dumb.c program from above, with
> just another reference:
>
> int
> dumb2(int *restrict a, int *restrict *restrict ap)
> {
> // We don't access the objects
> return a == *ap;
> }
>
> int
> main(void)
> {
> int x = 3;
> int *xp = &x;
>
> return dumb2(&x, &xp);
> }
>
> GCC doesn't report anything bad here, even though it's basically the
> same as the program from above:
>
> $ cc -Wall -Wextra dumb2.c
> $
strtol does have a "char * restrict * restrict" though, so the
situation is different. A "char **" and a "const char *"
shouldn't alias anyway.
>
> Again, there's no UB, but we really want to be cautious and get a
> diagnostic as callers, just in case the callee decides to access the
> object; we never know.
>
> So, GCC should be patched to report a warning in the program above.
> That will also cause strtol(3) to start issuing warnings in use cases
> like the one I showed.
>
> Even further, let's try something really weird: inequality comparison,
> which is only defined for pointers to the same array object:
>
> int
> dumb3(int *restrict a, int *restrict *restrict ap)
> {
> // We don't access the objects
> return a > *ap;
> }
>
> int
> main(void)
> {
> int x = 3;
> int *xp = &x;
>
> return dumb3(&x, &xp);
> }
>
> The behavior is still defined, since the obnjects are not accessed, but
> the compiler should really warn, on both sides:
>
> - The caller is passing references to the same object in restricted
> parameters, which is a red flag.
>
> - The callee is comparing for inequality pointers that should, under
> normal circumstances, cause Undefined Behavior.
>
>
> > And if this is really wrong you should report it to WG14 before changing
> > glibc.
>
> Well, I don't know how to report that defect to WG14. If you help me,
> I'll be pleased to do so. Do they have a public mailing list or
> anything like that?
One can submit clarification or change requests:
https://www.open-std.org/jtc1/sc22/wg14/www/contributing.html
Martin