[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
        $

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?


Cheers,
Alex

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

Attachment: signature.asc
Description: PGP signature

Reply via email to