The attached patch extends -Wrestrict to constrain valid offset ranges into objects of struct types to the bounds of the object type, the same way the warning already handles arrays. This makes it possible to detect overlapping accesses in cases like the second call to memcpy below:
char a[16]; struct { char a[16]; } x; void f (int i, int j) { memcpy (&a[i], &a[j], 9); // -Wrestrict (good) memcpy (&x.a[i], &x.a[j], 9); // missing -Wrestrict } These is no way to copy 9 bytes within a 16 byte array without either overlap or without accessing memory outside the bounaries of the object. This is for GCC 9. Thanks Martin
PR tree-optimization/85753 - missing -Wrestrict on memcpy into a member array gcc/ChangeLog: PR tree-optimization/85753 * gimple-ssa-warn-restrict.c (builtin_memref::builtin_memref): Handle RECORD_TYPE in addition to ARRAY_TYPE. gcc/testsuite/ChangeLog: PR tree-optimization/85753 * gcc.dg/Wrestrict-10.c: Adjust. * gcc.dg/Wrestrict-16.c: New test. diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 3d0664d..f461b84 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -263,27 +263,33 @@ builtin_memref::builtin_memref (tree expr, tree size) else sizrange[1] = maxobjsize; + if (!DECL_P (base)) + return; + tree basetype = TREE_TYPE (base); - if (DECL_P (base) && TREE_CODE (basetype) == ARRAY_TYPE) + if (TREE_CODE (basetype) != ARRAY_TYPE + && TREE_CODE (basetype) != RECORD_TYPE) + return; + + /* If the offset could be in the range of the referenced object + constrain its bounds so neither exceeds those of the object. */ + if (offrange[0] < 0 && offrange[1] > 0) + offrange[0] = 0; + + offset_int maxoff = maxobjsize; + if (TREE_CODE (basetype) == ARRAY_TYPE + && ref + && array_at_struct_end_p (ref)) + ; /* Use the maximum possible offset for last member arrays. */ + else if (tree basesize = TYPE_SIZE_UNIT (basetype)) + maxoff = wi::to_offset (basesize); + + if (offrange[0] >= 0) { - /* If the offset could be in range of the referenced object - constrain its bounds so neither exceeds those of the object. */ - if (offrange[0] < 0 && offrange[1] > 0) - offrange[0] = 0; - - offset_int maxoff = maxobjsize; - if (ref && array_at_struct_end_p (ref)) - ; /* Use the maximum possible offset for last member arrays. */ - else if (tree basesize = TYPE_SIZE_UNIT (basetype)) - maxoff = wi::to_offset (basesize); - - if (offrange[0] >= 0) - { - if (offrange[1] < 0) - offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize; - else if (offrange[0] <= maxoff && offrange[1] > maxoff) - offrange[1] = maxoff; - } + if (offrange[1] < 0) + offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize; + else if (offrange[0] <= maxoff && offrange[1] > maxoff) + offrange[1] = maxoff; } } diff --git a/gcc/testsuite/gcc.dg/Wrestrict-10.c b/gcc/testsuite/gcc.dg/Wrestrict-10.c index a5a5ff1..c412e42 100644 --- a/gcc/testsuite/gcc.dg/Wrestrict-10.c +++ b/gcc/testsuite/gcc.dg/Wrestrict-10.c @@ -58,7 +58,7 @@ test_arr_strncat_2 (void) void __attribute__ ((noclone, noinline)) test_arr_strcpy_1 (void) { - strcpy (&b.a[i], b.a); + strcpy (&b.a[i], b.a); /* { dg-warning "\\\[-Wrestrict" } */ } void __attribute__ ((noclone, noinline)) diff --git a/gcc/testsuite/gcc.dg/Wrestrict-16.c b/gcc/testsuite/gcc.dg/Wrestrict-16.c new file mode 100644 index 0000000..136e122 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-16.c @@ -0,0 +1,34 @@ +/* PR tree-optimization/85753 - missing -Wrestrict on memcpy into a member + array + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define memcpy __builtin_memcpy + +char a[16]; + +struct { char a[16]; } x; + +void test_idx_nowarn (int i, int j) +{ + memcpy (&a[i], &a[j], 7); + memcpy (&x.a[i], &x.a[j], 7); +} + +void test_idx_warn (int i, int j) +{ + memcpy (&a[i], &a[j], 9); /* { dg-warning "\\\[-Wrestrict" } */ + memcpy (&x.a[i], &x.a[j], 9); /* { dg-warning "\\\[-Wrestrict" } */ +} + +void test_off_nowarn (int i, int j) +{ + memcpy (a + i, a + j, 5); + memcpy (x.a + i, x.a + j, 5); +} + +void test_off_warn (int i, int j) +{ + memcpy (a + i, a + j, 9); /* { dg-warning "\\\[-Wrestrict" } */ + memcpy (x.a + i, x.a + j, 9); /* { dg-warning "\\\[-Wrestrict" } */ +}