1  /* PR middle-end/85602 - -Wsizeof-pointer-memaccess for strncat with size
       2     of source
       3     { dg-do compile }
       4     { dg-options "-O2 -Wno-array-bounds -Wsizeof-pointer-memaccess -Wstringop-truncation -ftrack-macro-expansion=0" } */
       5  
       6  #include "../gcc.dg/range.h"
       7  
       8  typedef __SIZE_TYPE__ size_t;
       9  
      10  #if __cplusplus
      11  extern "C" {
      12  #endif
      13  
      14  char* strcpy (char*, const char*);
      15  size_t strlen (const char*);
      16  char* strncat (char*, const char*, __SIZE_TYPE__);
      17  char* strncpy (char*, const char*, __SIZE_TYPE__);
      18  
      19  #if __cplusplus
      20  }
      21  #endif
      22  
      23  #define NONSTR __attribute__ ((nonstring))
      24  
      25  NONSTR char nd3[3];
      26  NONSTR char nd4[4];
      27  NONSTR char nd5[5];
      28  
      29  NONSTR char ns3[3];
      30  NONSTR char ns4[4];
      31  NONSTR char ns5[5];
      32  
      33  NONSTR char* pns;
      34  
      35  void sink (void*, ...);
      36  
      37  #define T(call) sink (call)
      38  
      39  /* Verify that for a nonstring source array of an unknown length
      40     a warning is issued only when the bound exceeds the array size.  */
      41  
      42  void test_strncat_nonstring_cst (char *d)
      43  {
      44    T (strncat (d, ns3, 1));
      45    T (strncat (d, ns3, 2));
      46    T (strncat (d, ns3, 3));
      47    T (strncat (d, ns3, sizeof ns3));
      48    T (strncat (d, ns3, 4));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
      49  
      50    T (strncat (d, ns4, 1));
      51    T (strncat (d, ns4, 2));
      52    T (strncat (d, ns4, 3));
      53    T (strncat (d, ns4, 4));
      54    T (strncat (d, ns4, sizeof ns4));
      55    T (strncat (d, ns4, 5));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 5" } */
      56  
      57    T (strncat (nd3, ns3, 1));
      58    T (strncat (nd3, ns3, 2));
      59    T (strncat (nd3, ns3, 3));     /* { dg-warning "specified bound 3 equals destination size" } */
      60    /* Either of the two warnings below is fine.  */
      61    T (strncat (nd3, ns3, 4));     /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4|specified bound 4 exceeds destination size 3" } */
      62  
      63    T (strncat (d, pns, sizeof pns));   /* { dg-warning "argument to .sizeof. in .\[^\n\r\]*strncat\[^\n\r\]*. call is the same expression as the source" } */
      64  }
      65  
      66  
      67  void test_strncat_nonstring_var (char *d, size_t n)
      68  {
      69    /* In the following the bound coulld apply to either the destination
      70       or the source.  The expected use of strncat() is to pass it as
      71       the bound DSIZE - strlen(D) - 1 so the call below is diagnosed.  */
      72    T (strncat (d, ns3, n));            /* { dg-warning "argument 2 declared attribute .nonstring." } */
      73  
      74    T (strncat (d, ns3, UR (0, 1)));
      75    T (strncat (d, ns3, UR (1, 2)));
      76    T (strncat (d, ns3, UR (2, 3)));
      77    T (strncat (d, ns3, UR (3, 4)));    /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
      78    T (strncat (d, ns3, UR (4, 5)));    /* { dg-warning "argument 2 declared attribute 'nonstring' is smaller than the specified bound \\\[4, 5]" } */
      79  
      80    /* Verify that the call below (the intended use of strncat()) is
      81       also diagnosed.  */
      82    T (strncat (d, ns3, 256 - strlen (d) - 1));   /* { dg-warning "argument 2 declared attribute .nonstring." } */
      83  
      84    T (strncat (nd3, ns5, UR (0, 1)));
      85    T (strncat (nd3, ns5, UR (1, 2)));
      86    T (strncat (nd3, ns5, UR (2, 3)));
      87    T (strncat (nd3, ns5, UR (3, 4)));
      88    T (strncat (nd3, ns5, UR (4, 5)));  /* { dg-warning "specified bound \\\[4, 5] exceeds destination size 3" } */
      89  
      90    T (strncat (nd5, ns3, UR (0, 1)));
      91    T (strncat (nd5, ns3, UR (1, 2)));
      92    T (strncat (nd5, ns3, UR (2, 3)));
      93    T (strncat (nd5, ns3, UR (3, 4)));  /* { dg-warning "argument 2 declared attribute 'nonstring' may be smaller than the specified bound \\\[3, 4]" } */
      94  }
      95  
      96  /* Verify that for a nonstring source array of a known length (i.e.,
      97     a nonstring array containing a nul-terminated string) a warning
      98     is issued only for certain truncation.
      99  
     100     The test cases are split up to work around bug 81343 (or one like
     101     it).  */
     102  
     103  void test_strncat_string_1_1 (char *d)
     104  {
     105    strcpy (ns3, "1");
     106    T (strncat (d, ns3, 1));    /* { dg-warning "output truncated before terminating nul copying 1 byte from a string of the same length" } */
     107  }
     108  
     109  void test_strncat_string_1_2 (char *d)
     110  {
     111    strcpy (ns3, "1");
     112    T (strncat (d, ns3, 2));
     113  }
     114  
     115  void test_strncat_string_1_3 (char *d)
     116  {
     117    strcpy (ns3, "1");
     118    T (strncat (d, ns3, 3));
     119  }
     120  
     121  void test_strncat_string_2_1 (char *d)
     122  {
     123    strcpy (ns3, "12");
     124    T (strncat (d, ns3, 1));    /* { dg-warning "output truncated copying 1 byte from a string of length 2" } */
     125  }
     126  
     127  void test_strncat_string_2_2 (char *d)
     128  {
     129    strcpy (ns3, "12");
     130    T (strncat (d, ns3, 2));    /* { dg-warning "output truncated before terminating nul copying 2 bytes from a string of the same length" } */
     131  }
     132  
     133  void test_strncat_string_2_3 (char *d)
     134  {
     135    strcpy (ns3, "12");
     136    T (strncat (d, ns3, 3));
     137  }
     138  
     139  
     140  void test_strcncpy_nonstring_cst (char *d)
     141  {
     142    T (strncpy (d, ns3, 1));
     143    T (strncpy (d, ns3, 2));
     144    T (strncpy (d, ns3, 3));
     145    T (strncpy (d, ns3, sizeof ns3));
     146    T (strncpy (d, ns3, 4));      /* { dg-warning "argument 2 declared attribute .nonstring. is smaller than the specified bound 4" } */
     147  }