(root)/
gcc-13.2.0/
gcc/
testsuite/
c-c++-common/
Warray-bounds-3.c
       1  /* Exercise that -Warray-bounds is issued for out-of-bounds offsets
       2     in calls to built-in functions.
       3     { dg-do compile }
       4     { dg-options "-O2 -Wno-stringop-overflow -Warray-bounds -ftrack-macro-expansion=0" }  */
       5  
       6  #include "../gcc.dg/range.h"
       7  
       8  #if __cplusplus
       9  #  define restrict __restrict
      10  extern "C" {
      11  #endif
      12  
      13  extern void* memcpy (void* restrict, const void* restrict, size_t);
      14  extern void* mempcpy (void* restrict, const void* restrict, size_t);
      15  extern void* memmove (void*, const void*, size_t);
      16  
      17  extern char* stpcpy (char* restrict, const char* restrict);
      18  
      19  extern char* strcat (char* restrict, const char* restrict);
      20  extern char* strcpy (char* restrict, const char* restrict);
      21  extern char* strncpy (char* restrict, const char* restrict, size_t);
      22  
      23  #if __cplusplus
      24  }   /* extern "C" */
      25  #endif
      26  
      27  void sink (void*, ...);
      28  
      29  #define CAT(x, y)      x ## y
      30  #define CONCAT(x, y)   CAT (x, y)
      31  #define UNIQUE_NAME(x) CONCAT(x, __LINE__)
      32  
      33  #define T(type, N, dst, src, n) do {		\
      34      extern type UNIQUE_NAME (a)[N];		\
      35      type *a = UNIQUE_NAME (a);			\
      36      type *pd = (dst);				\
      37      const type *ps = (src);			\
      38      FUNC (pd, ps, n);				\
      39      sink (a, pd, ps);				\
      40    } while (0)
      41  
      42  
      43  void test_memcpy_bounds (char *d, const char *s, size_t n)
      44  {
      45  #define FUNC memcpy
      46  
      47    /* Verify that invalid offsets into an array of known size are
      48       detected.  */
      49  
      50    T (char, 1, a + SR (DIFF_MIN, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds \\\[0, 1] of object \[^\n\r]* with type .char ?\\\[1]" } */
      51    T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds \\\[0, 1] of object" } */
      52    T (char, 1, a + SR (-2, 0), s, n);
      53  
      54    T (char, 1, a + UR (0, 1), s, n);
      55    T (char, 1, a + UR (0, 2), s, n);
      56    T (char, 1, a + UR (1, 2), s, n);
      57    T (char, 1, a + UR (2, 3), s, n);       /* { dg-warning "offset \\\[2, 3] is out of the bounds \\\[0, 1] of object " } */
      58    T (char, 1, a + UR (2, DIFF_MAX), s, n);  /* { dg-warning "offset \\\[2, \[0-9\]+] is out of the bounds \\\[0, 1] of object " "memcpy" } */
      59  
      60    /* Offsets in excess of DIFF_MAX are treated as negative even if
      61       they appear as large positive in the source.  It would be nice
      62       if they retained their type but unfortunately that's not how
      63       it works so be prepared for both in case it even gets fixed.  */
      64    T (char, 1, a + UR (3, SIZE_MAX - 1), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object" "memcpy" } */
      65  
      66    /* Verify that invalid offsets into an array of unknown size are
      67       detected.  */
      68    extern char arr[];
      69    T (char, 1, arr + SR (DIFF_MIN,             0), s, n);
      70    T (char, 1, arr + SR (DIFF_MIN + 1,        -1), s, n);   /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds of object " "memcpy" } */
      71    T (char, 1, arr + SR (DIFF_MIN,             1), s, n);
      72    T (char, 1, arr + SR (DIFF_MIN,      DIFF_MAX), s, n);
      73    T (char, 1, arr + SR (       -2,           -1), s, n);   /* { dg-warning "offset \\\[-2, -1] is out of the bounds of object " "memcpy" } */
      74    T (char, 1, arr + SR (       -1,            0), s, n);
      75    T (char, 1, arr + SR (       -1,            1), s, n);
      76    T (char, 1, arr + SR (       -1, DIFF_MAX - 1), s, n);
      77    T (char, 1, arr + SR (        0,            1), s, n);
      78    T (char, 1, arr + SR (        0, DIFF_MAX - 1), s, n);
      79    T (char, 1, arr + SR (        1,            2), s, n);
      80    T (char, 1, arr + SR (        1, DIFF_MAX - 1), s, n);
      81  
      82    /* Verify that all offsets via a pointer to an uknown object are
      83       accepted.  */
      84  
      85    /* Negative indices between [DIFF_MIN, DIFF_MAX] are valid since
      86       the pointer to which the offset is applied can be at a positive
      87       offset from the beginning of an object.  */
      88    T (char, 1, d + SR (DIFF_MIN,             0), s, n);
      89    T (char, 1, d + SR (DIFF_MIN,            -1), s, n);
      90    T (char, 1, d + SR (DIFF_MIN,             1), s, n);
      91    T (char, 1, d + SR (DIFF_MIN,  DIFF_MAX - 1), s, n);
      92    T (char, 1, d + SR (       -2,           -1), s, n);
      93    T (char, 1, d + SR (       -1,            0), s, n);
      94    T (char, 1, d + SR (       -1,            1), s, n);
      95    T (char, 1, d + SR (       -1, DIFF_MAX - 1), s, n);
      96    T (char, 1, d + SR (        0,            1), s, n);
      97    T (char, 1, d + SR (        0, DIFF_MAX - 1), s, n);
      98    T (char, 1, d + SR (        1,            2), s, n);
      99    T (char, 1, d + SR (        1, DIFF_MAX - 1), s, n);
     100  }
     101  
     102  /* Verify offsets in an anti-range.  */
     103  
     104  void test_memcpy_bounds_anti_range (char *d, const char *s, size_t n)
     105  {
     106    T (char, 9, a, a + SAR (-2, -1), 3);
     107    T (char, 9, a, a + SAR (-1,  1), 3);
     108    T (char, 9, a, a + SAR ( 0,  1), 3);
     109    T (char, 9, a, a + SAR ( 0,  2), 3);
     110    T (char, 9, a, a + SAR ( 0,  3), 3);
     111    T (char, 9, a, a + SAR ( 0,  4), 3);
     112    T (char, 9, a, a + SAR ( 0,  5), 3);
     113    /* The initial source range is valid but the final range after the access
     114       has complete cannot be.  The value mentioned in the warning is the final
     115       offset, i.e., 7 + 3.  Including the whole final range because would be
     116       confusing (the upper bound would either be negative or a very large
     117       positive number) so only the lower bound is included.  */
     118    T (char, 9, a, a + SAR ( 0,  6), 3);   /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */
     119  
     120    /* This fails because the offset isn't represented as an SSA_NAME
     121       but rather as a GIMPLE_PHI (offset, 0).  With some effort it is
     122       possible to extract the range from the PHI but it's not implemented
     123       (yet).  */
     124    T (char, 9, a, a + SAR ( 1,  6), 3);   /* { dg-warning "forming offset \\\[9, 0] is out of the bounds \\\[0, 9] of object " "memcpy" { xfail *-*-* } } */
     125  
     126    /* The range of offsets is the union of [0, 1] and [7, PTRDIFF_MAX]
     127       of which the first subrange is valid and thus no warming for memcpy
     128       is issued.  Similarly for the next test.  */
     129    T (char, 9, a, a + SAR ( 2,  6), 3);
     130    T (char, 9, a, a + SAR ( 3,  6), 3);
     131  
     132    T (char, 9, a, a + SAR (-1,  7), 3);   /* { dg-warning "forming offset \\\[9, 10] is out of the bounds \\\[0, 9] of object " "memcpy" } */
     133    T (char, 9, a, a + SAR (-2,  8), 3);   /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */
     134    T (char, 9, a, a + SAR (-3,  7), 5);   /* { dg-warning "forming offset \\\[9, 12] is out of the bounds \\\[0, 9] of object " "memcpy" } */
     135  
     136    T (char, 9, a + SAR (-2, -1), a, 3);
     137    T (char, 9, a + SAR (-1,  1), a, 3);
     138    T (char, 9, a + SAR ( 0,  1), a, 3);
     139    T (char, 9, a + SAR ( 0,  2), a, 3);
     140    T (char, 9, a + SAR ( 0,  3), a, 3);
     141    T (char, 9, a + SAR ( 0,  6), a, 3);   /* { dg-warning "forming offset 9 is out of the bounds \\\[0, 9] of object " "memcpy" } */
     142    T (char, 9, a + SAR (-1,  7), a, 3);   /* { dg-warning "forming offset \\\[9, 10] is out of the bounds \\\[0, 9] of object " "memcpy" } */
     143    T (char, 9, a + SAR (-2,  8), a, 3);   /* { dg-warning "offset \\\[9, 11] is out of the bounds \\\[0, 9] of object " "memcpy" } */
     144  
     145    ptrdiff_t i = SAR (DIFF_MIN + 1, DIFF_MAX - 4);
     146    T (char, 1, d, d + SAR (DIFF_MIN + 3, DIFF_MAX - 1), 3);
     147    T (char, 1, d, d + SAR (DIFF_MIN + 3, DIFF_MAX - 3), 5);
     148  }
     149  
     150  /* Verify that pointer overflow in the computation done by memcpy
     151     (i.e., offset + size) is detected and diagnosed.  */
     152  
     153  void test_memcpy_overflow (char *d, const char *s, size_t n)
     154  {
     155    extern char arr[];
     156  
     157    /* Verify that offset overflow involving an array of unknown size
     158       but known access size is detected.  This works except with small
     159       sizes that are powers of 2 due to bug .  */
     160    T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 1);
     161    T (char, 1, arr + SR (DIFF_MAX - 1, DIFF_MAX), s, 2);  /* { dg-warning "\\\[-Warray-bounds" } */
     162    T (char, 1, arr + SR (DIFF_MAX - 2, DIFF_MAX), s, 3);  /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 3 accessing array " "memcpy" } */
     163    T (char, 1, arr + SR (DIFF_MAX - 4, DIFF_MAX), s, 5);  /* { dg-warning "pointer overflow between offset \\\[\[0-9\]+, \[0-9\]+] and size 5 accessing array " "memcpy" } */
     164  }
     165  
     166  void test_memcpy_bounds_memarray_range (void)
     167  {
     168  #undef TM
     169  #define TM(mem, dst, src, n)			\
     170    do {						\
     171      struct MA { char a5[5]; int i; } ma;	\
     172      sink (&ma);   /* Initialize arrays.  */	\
     173      memcpy (dst, src, n);			\
     174      sink (&ma);					\
     175    } while (0)
     176  
     177    ptrdiff_t i = SR (1, 2);
     178  
     179    TM (ma.a5, ma.a5 + i, ma.a5, 1);
     180    TM (ma.a5, ma.a5 + i, ma.a5, 3);
     181    TM (ma.a5, ma.a5 + i, ma.a5, 5);     /* { dg-warning "\\\[-Warray-bounds" "pr101374" { xfail *-*-* } } */
     182    TM (ma.a5, ma.a5 + i, ma.a5, 7);     /* diagnosed with -Warray-bounds=2 */
     183  }
     184  
     185  void test_memmove_bounds (char *d, const char *s, size_t n)
     186  {
     187  #undef FUNC
     188  #define FUNC memmove
     189  
     190      T (char, 1, a + SR (DIFF_MIN + 1, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds \\\[0, 1] of object \[^\n\r]+ with type .char ?\\\[1]" } */
     191    T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds \\\[0, 1] of object" } */
     192    T (char, 1, a + SR (-2, 0), s, n);
     193  
     194    const int *pi = (const int*)s;
     195    T (int,  2, a + SR (-1, 1), pi, n);
     196    T (int,  2, a + SR (-1, 2), pi, n);
     197    T (int,  2, a + SR ( 0, 2), pi, n);
     198    T (int,  2, a + SR ( 0, 3), pi, n);
     199    T (int,  2, a + SR ( 1, 3), pi, n);
     200    T (int,  2, a + SR ( 2, 3), pi, n);
     201  
     202    const int32_t *pi32 = (const int32_t*)s;
     203    T (int32_t, 2, a + SR ( 3, 4), pi32, n);      /* { dg-warning "offset \\\[12, 16] is out of the bounds \\\[0, 8] of object .\[^\n\r]+. with type .int32_t ?\\\[2]." } */
     204  }
     205  
     206  
     207  void test_mempcpy_bounds (char *d, const char *s, size_t n)
     208  {
     209  #undef FUNC
     210  #define FUNC mempcpy
     211  
     212    /* Verify that invalid offsets into an array of known size are
     213       detected.  */
     214  
     215    T (char, 1, a + SR (DIFF_MIN, -1), s, n);     /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds"  "mempcpy" } */
     216  T (char, 1, a + SR (-2, -1), s, n);     /* { dg-warning "offset \\\[-2, -1] is out of the bounds"  "mempcpy" } */
     217    T (char, 1, a + SR (-2, 0), s, n);
     218  
     219    T (char, 1, a + UR (0, 1), s, n);
     220    T (char, 1, a + UR (0, 2), s, n);
     221    T (char, 1, a + UR (1, 2), s, n);
     222    T (char, 1, a + UR (2, 3), s, n);       /* { dg-warning "offset \\\[2, 3] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
     223    T (char, 1, a + UR (2, DIFF_MAX), s, n);  /* { dg-warning "offset \\\[2, \[0-9\]+] is out of the bounds \\\[0, 1] of object"  "mempcpy" } */
     224  
     225    /* Offsets in excess of DIFF_MAX are treated as negative even if
     226       they appear as large positive in the source.  It would be nice
     227       if they retained their type but unfortunately that's not how
     228       it works so be prepared for both in case it ever gets fixed.  */
     229    T (char, 1, a + UR (3, SIZE_MAX), s, n);   /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object "  "mempcpy" } */
     230  
     231    /* Verify that invalid offsets into an array of unknown size are
     232       detected.  */
     233    extern char arr[];
     234    T (char, 1, arr + SR (DIFF_MIN,         0), s, n);
     235    T (char, 1, arr + SR (DIFF_MIN,        -1), s, n);   /* { dg-warning "offset \\\[-\[0-9\]+, -1] is out of the bounds of object"  "mempcpy" } */
     236    T (char, 1, arr + SR (DIFF_MIN,         1), s, n);
     237    T (char, 1, arr + SR (DIFF_MIN, DIFF_MAX), s, n);
     238    T (char, 1, arr + SR (       -2,        -1), s, n);   /* { dg-warning "offset \\\[-2, -1] is out of the bounds of object"  "mempcpy" } */
     239    T (char, 1, arr + SR (       -1,         0), s, n);
     240    T (char, 1, arr + SR (       -1,         1), s, n);
     241    T (char, 1, arr + SR (       -1, DIFF_MAX), s, n);
     242    T (char, 1, arr + SR (        0,         1), s, n);
     243    T (char, 1, arr + SR (        0, DIFF_MAX), s, n);
     244    T (char, 1, arr + SR (        1,         2), s, n);
     245    T (char, 1, arr + SR (        1, DIFF_MAX), s, n);
     246  
     247    /* Verify that all offsets via a pointer to an uknown object are
     248       accepted.  */
     249  
     250    /* Negative indices between [DIFF_MIN, DIFF_MAX] are valid since
     251       the pointer to which the offset is applied can be at a positive
     252       offset from the beginning of an object.  */
     253    T (char, 1, d + SR (DIFF_MIN,         0), s, n);
     254    T (char, 1, d + SR (DIFF_MIN,        -1), s, n);
     255    T (char, 1, d + SR (DIFF_MIN,         1), s, n);
     256    T (char, 1, d + SR (DIFF_MIN, DIFF_MAX), s, n);
     257    T (char, 1, d + SR (       -2,        -1), s, n);
     258    T (char, 1, d + SR (       -1,         0), s, n);
     259    T (char, 1, d + SR (       -1,         1), s, n);
     260    T (char, 1, d + SR (       -1, DIFF_MAX), s, n);
     261    T (char, 1, d + SR (        0,         1), s, n);
     262    T (char, 1, d + SR (        0, DIFF_MAX), s, n);
     263    T (char, 1, d + SR (        1,         2), s, n);
     264    T (char, 1, d + SR (        1, DIFF_MAX), s, n);
     265  }
     266  
     267  #define TI(type, N, init, dst, src) do {	\
     268      type UNIQUE_NAME (a)[N] = init;		\
     269      type *a = UNIQUE_NAME (a);			\
     270      type *pd = (dst);				\
     271      const type *ps = (src);			\
     272      FUNC (pd, ps);				\
     273      sink (a, pd, ps, s);			\
     274    } while (0)
     275  
     276  void test_strcpy_bounds (char *d, const char *s)
     277  {
     278  #undef FUNC
     279  #define FUNC strcpy
     280  
     281    ptrdiff_t i;
     282  
     283    TI (char, 1, "",   a, a + SR (DIFF_MIN, 0));
     284    TI (char, 1, "",   a, a + SR (-1, 0));
     285    TI (char, 1, "",   a, a + SR (-1, 1));
     286    TI (char, 1, "",   a, a + SR (0, 1));
     287    TI (char, 1, "",   a, a + SR (0, DIFF_MAX - 1));
     288    TI (char, 2, "0",  a, a + SR (0, DIFF_MAX - 1));
     289    TI (char, 2, "0",  a, a + SR (1, DIFF_MAX - 1));
     290    /* The warning below isn't the most accurate because while reading
     291       from it is invalid, the offset that refers just past the end of
     292       the source array is strictly valid.  */
     293    TI (char, 2, "0",  a, a + SR (2, DIFF_MAX - 1));    /* { dg-warning "offset 2 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type 'char ?\\\[2]'" } */
     294    TI (char, 2, "0",  a, a + SR (3, DIFF_MAX - 1));   /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
     295  
     296    TI (char, 3, "01", a, a + SR (0, DIFF_MAX - 1));
     297    TI (char, 3, "01", a, a + SR (1, DIFF_MAX - 1));
     298    TI (char, 3, "01", a, a + SR (2, DIFF_MAX - 1));
     299    TI (char, 3, "01", a, a + SR (3, DIFF_MAX - 1));   /* { dg-warning "offset 3 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type 'char ?\\\[3]'" } */
     300    TI (char, 3, "01", a, a + SR (4, DIFF_MAX - 1));   /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
     301  
     302    TI (char, 4, "012", a, a + SR (DIFF_MAX - 2, DIFF_MAX - 1));   /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]."  "strcpy" } */
     303  
     304  
     305    TI (char, 1, "", a + SR (DIFF_MIN, 0), s);
     306    TI (char, 1, "", a + SR (-1, 0), s);
     307    TI (char, 1, "", a + SR (-1, 1), s);
     308    TI (char, 1, "", a + SR (0, 1), s);
     309    TI (char, 1, "", a + SR (0, DIFF_MAX - 1), s);
     310    TI (char, 2, "", a + SR (0, DIFF_MAX - 1), s);
     311    TI (char, 2, "", a + SR (1, DIFF_MAX - 1), s);
     312    /* The following is diagnosed not because the initial source offset
     313       it out of bounds (it isn't) but because the final source offset
     314       after the access has completed, is.  It would be clearer if
     315       the warning mentioned the final offset.  */
     316    TI (char, 2, "", a + SR (2, DIFF_MAX - 1), s);   /* { dg-warning "offset 2 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
     317    TI (char, 2, "", a + SR (3, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]."  "strcpy" } */
     318  
     319    TI (char, 3, "", a + SR (0, DIFF_MAX - 1), s);
     320    TI (char, 3, "", a + SR (1, DIFF_MAX - 1), s);
     321    TI (char, 3, "", a + SR (2, DIFF_MAX - 1), s);
     322    TI (char, 3, "", a + SR (3, DIFF_MAX - 1), s);   /* { dg-warning "offset 3 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
     323    TI (char, 3, "", a + SR (4, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]."  "strcpy" } */
     324  
     325    TI (char, 4, "", a + SR (DIFF_MAX - 2, DIFF_MAX - 1), s);   /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]."  "strcpy" } */
     326  }
     327  
     328  struct MA
     329  {
     330  #if __SIZEOF_INT__ == 2
     331    long i;
     332  #else
     333    int i;
     334  #endif
     335    char a5[5];
     336    char a11[11];
     337  };
     338  
     339  struct MA2
     340  {
     341    struct MA ma3[3];
     342    struct MA ma5[5];
     343    char ax[];
     344  };
     345  
     346  struct MA3
     347  {
     348    struct MA2 ma5[3];
     349    struct MA2 ma7[7];
     350  };
     351  
     352  void test_strcpy_bounds_memarray_range (void)
     353  {
     354  #undef TM
     355  #define TM(mem, init, dst, src)			\
     356    do {						\
     357      struct MA ma;				\
     358      strcpy (ma.mem, init);			\
     359      strcpy (dst, src);				\
     360      sink (&ma);					\
     361    } while (0)
     362  
     363    ptrdiff_t i = SR (1, 2);
     364  
     365    TM (a5, "0",    ma.a5 + i, ma.a5);
     366    TM (a5, "01",   ma.a5 + i, ma.a5);
     367    TM (a5, "012",  ma.a5 + i, ma.a5);
     368    TM (a5, "0123", ma.a5 + i, ma.a5);     /* { dg-warning "offset 9 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]. at offset 4" "strcpy" } */
     369  
     370    TM (a11, "0",       ma.a5, ma.a11);
     371    TM (a11, "01",      ma.a5, ma.a11);
     372    TM (a11, "012",     ma.a5, ma.a11);
     373    TM (a11, "0123",    ma.a5, ma.a11);
     374    TM (a11, "01234",   ma.a5, ma.a11);    /* { dg-warning "offset 9 from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
     375    TM (a11, "012345",  ma.a5, ma.a11);    /* { dg-warning "offset \\\[9, 10] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
     376    TM (a11, "0123456", ma.a5, ma.a11);    /* { dg-warning "offset \\\[9, 11] from the object at .ma. is out of the bounds of referenced subobject .\(MA::\)?a5. with type .char ?\\\[5]' at offset 4" } */
     377  
     378    TM (a11, "0123456", ma.a11 + i, "789abcd");
     379  }
     380  
     381  void test_strcpy_bounds_memarray_var (struct MA *pma,
     382  				      struct MA2 *pma2,
     383  				      struct MA3 *pma3,
     384  				      const char *s, size_t n)
     385  {
     386  #undef TM
     387  #define TM(dst, src) do {			\
     388      strcpy (dst, src);				\
     389      sink (dst, src);				\
     390    } while (0)
     391  
     392    TM (pma->a5, s);
     393    TM (pma->a5 + 0, s);
     394    TM (pma->a5 + 1, s);
     395    TM (pma->a5 + 4, s);
     396  
     397    /* The following forms a pointer during the call that's outside
     398       the bounds of the array it was derived from (pma->a5) so
     399       it should be diagnosed but the representation of the pointer
     400       addition doesn't contain information to distinguish it from
     401       the valid pma->a11 + 1 so this is an XFAIL.  */
     402    TM (pma->a5 + 5, s);                 /* { dg-warning "offset 17 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
     403  
     404    /* The following also forms an out-of-bounds pointer but similar
     405       to the above, there is no reliable way to distinguish it from
     406       (char*)&pma[1].i + 1 so this too is not diagnosed.  */
     407    TM (pma->a5 + sizeof *pma + 1, s);   /* { dg-warning "offset 17 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
     408  
     409    TM (pma->a5 - 1, s);   /* { dg-warning "offset -1 from the object at .pma. is out of the bounds of .struct MA." "strcpy" { xfail *-*-* } } */
     410  
     411    TM (pma[1].a5, s);
     412    TM (pma[2].a5 + 0, s);
     413    TM (pma[3].a5 + 1, s);
     414    TM (pma[4].a5 + 4, s);
     415  
     416  
     417    extern struct MA3 ma3[3];
     418    TM (ma3[0].ma5[0].ma3[0].a5 + 6, s);
     419  }