Wednesday, 28 December 2016

Wrestrict

I added Wrestrict in GCC 7 that emits diagnostic when same arguments are passed to
a function whose corresponding parameters are restrict qualified.

Example:

  1. void f(void)
  2. {
  3.   char buf[100] = "hello";
  4.   sprintf (buf, "%s-%s", buf, "world");
  5. }

Compiling with -Wrestrict shows:

foo.c: In function ‘f’:
foo.c:6:8: warning: passing argument 1 to restrict-qualified parameter aliases with
argument 3 [-Wrestrict]
   sprintf (buf, "%s-%s", buf, "world");
               ^~~                  ~~~

However the warning can emit false positives, because it only looks at function's parameters and
not at how they are used in function.

N1570 6.7.3.1 Example 3:
  1. void h(int n, int * restrict p, int * restrict q, int * restrict r)
  2. {
  3.   int i;
  4.   for (= 0; i < n; i++)
  5.     p[i] = q[i] + r[i];
  6. }
  7. h(100, a, b, b);


Although q and r are qualified as restrict, the behavior is still defined since b is not modified by call to h(). However there is no way of knowing this information during FE, and the warning gets emitted for the above call. To amend this situation somewhat, warning is not emitted if the parameter in question is const-qualified. For this reason, the warning is not enabled by Wall or even Wextra, but only with Wrestrict. The warning did find few issues in gdb and elsewhere as reported by Eric Gallanger and Tobias Burnus.

Further improvements

The warning can be improved to detect simple cases of aliasing for arguments to builtin
functions, as reported in PR78918

  1. void f (void *p, void *q, unsigned n)
  2. {
  3.   p = q;
  4.   memcpy (p, q, n);
  5. }

The warning could be extended to diagnose pointer assignments when a pointed defined in outer block scope is used to initialize a pointer within the block.

N1570 6.7.3.1 Example 4:
  1. {
  2.   int * restrict p1;
  3.   int * restrict q1;
  4.   p1 = q1; // undefined behavior
  5.   {
  6.     int * restrict p2 = p1; // valid
  7.     int * restrict q2 = q1; // valid
  8.     p1 = q2; // undefined behavior
  9.     p2 = q2; // undefined behavior
  10.   }
  11. }

In the above example, the assignments to p1 and p2 within the block could be diagnosed with Wrestrict.