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


Reply via email to