1  /* { dg-do compile }
       2     { dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" }
       3     { dg-require-effective-target int32plus } */
       4  
       5  typedef __SIZE_TYPE__  size_t;
       6  typedef __WCHAR_TYPE__ wchar_t;
       7  
       8  #define INT_MAX __INT_MAX__
       9  #define INT_MIN (-INT_MAX - 1)
      10  
      11  /* When debugging, define LINE to the line number of the test case to exercise
      12     and avoid exercising any of the others.  The buffer and objsize macros
      13     below make use of LINE to avoid warnings for other lines.  */
      14  #ifndef LINE
      15  # define LINE 0
      16  #endif
      17  
      18  void sink (char*, char*);
      19  
      20  int dummy_sprintf (char*, const char*, ...);
      21  
      22  char buffer [256];
      23  extern char *ptr;
      24  
      25  static int int_range (int min, int max)
      26  {
      27    extern int int_value (void);
      28    int n = int_value ();
      29    return n < min || max < n ? min : n;
      30  }
      31  
      32  /* Evaluate to an array of SIZE characters when non-negative, or to
      33     a pointer to an unknown object otherwise.  */
      34  #define buffer(size)					\
      35    ((0 <= size) ? buffer + sizeof buffer - (size) : ptr)
      36  
      37  /* Helper to expand function to either __builtin_f or dummy_f to
      38     make debugging GCC easy.  */
      39  #define FUNC(f)							\
      40    ((!LINE || LINE == __LINE__) ? __builtin_ ## f : dummy_ ## f)
      41  
      42  /* Macro to verify that calls to __builtin_sprintf (i.e., with no size
      43     argument) issue diagnostics by correctly determining the size of
      44     the destination buffer.  */
      45  #define T(size, ...)						\
      46    (FUNC (sprintf) (buffer (size),  __VA_ARGS__),		\
      47     sink (buffer, ptr))
      48  
      49  /* Return a signed integer in the range [MIN, MAX].  */
      50  #define R(min, max)  int_range (min, max)
      51  
      52  /* Verify warnings and ranges for certain overflow.  */
      53  void test_min_overflow (int i)
      54  {
      55    T (0, "%#hho", i);            /* { dg-warning "between 1 and 4 bytes" } */
      56    T (0, "%#1hho", i);           /* { dg-warning "between 1 and 4 bytes" } */
      57    T (0, "%#2hho", i);           /* { dg-warning "between 2 and 4 bytes" } */
      58    T (0, "%#3hho", i);           /* { dg-warning "between 3 and 4 bytes" } */
      59    T (0, "%#4hho", i);           /* { dg-warning "writing 4 bytes" } */
      60    T (0, "%#hho", R (-1,  0));   /* { dg-warning "between 1 and 4 bytes" } */
      61    T (0, "%#1hho", R (-1,  0));  /* { dg-warning "between 1 and 4 bytes" } */
      62    T (0, "%#2hho", R (-1,  0));  /* { dg-warning "between 2 and 4 bytes" } */
      63    T (0, "%#3hho", R (-1,  0));  /* { dg-warning "between 3 and 4 bytes" } */
      64    T (0, "%#4hho", R (-1,  0));  /* { dg-warning "writing 4 bytes" } */
      65    T (0, "%#hho", R (-1,  1));   /* { dg-warning "between 1 and 4 bytes" } */
      66    T (0, "%#1hho", R (-1,  1));  /* { dg-warning "between 1 and 4 bytes" } */
      67    T (0, "%#2hho", R (-1,  1));  /* { dg-warning "between 2 and 4 bytes" } */
      68    T (0, "%#3hho", R (-1,  1));  /* { dg-warning "between 3 and 4 bytes" } */
      69    T (0, "%#4hho", R (-1,  1));  /* { dg-warning "writing 4 bytes" } */
      70    T (0, "%#hho", R ( 0,  1));   /* { dg-warning "between 1 and 2 bytes" } */
      71    T (0, "%#1hho", R ( 0,  1));  /* { dg-warning "between 1 and 2 bytes" } */
      72    T (0, "%#2hho", R ( 0,  1));  /* { dg-warning "writing 2 bytes" } */
      73    T (0, "%#3hho", R ( 0,  1));  /* { dg-warning "writing 3 bytes" } */
      74    T (0, "%#4hho", R ( 0,  1));  /* { dg-warning "writing 4 bytes" } */
      75    T (0, "%#hho", R ( 1,  2));   /* { dg-warning "writing 2 bytes" } */
      76    T (0, "%#1hho", R ( 1,  2));  /* { dg-warning "writing 2 bytes" } */
      77    T (0, "%#2hho", R ( 1,  2));  /* { dg-warning "writing 2 bytes" } */
      78    T (0, "%#3hho", R ( 1,  2));  /* { dg-warning "writing 3 bytes" } */
      79    T (0, "%#4hho", R ( 1,  2));  /* { dg-warning "writing 4 bytes" } */
      80  
      81    T (0, "%#ho",  i);            /* { dg-warning "between 1 and 7 bytes" } */
      82    T (0, "%#.*ho",               /* { dg-warning "between 1 and 7 bytes" } */
      83       R (0, 2), i);
      84    T (0, "%#.*ho",               /* { dg-warning "between 1 and 7 bytes" } */
      85       R (1, 2), i);
      86    T (0, "%#.*ho",               /* { dg-warning "between 2 and 7 bytes" } */
      87       R (2, 3), i);
      88    T (0, "%#.*ho",               /* { dg-warning "between 3 and 7 bytes" } */
      89       R (3, 4), i);
      90    T (0, "%#.*ho",               /* { dg-warning "between 7 and 8 bytes" } */
      91       R (7, 8), i);
      92  
      93    T (0, "%#ho",  R (-1,  0));   /* { dg-warning "between 1 and 7 bytes" } */
      94    T (0, "%#ho",  R (-1,  1));   /* { dg-warning "between 1 and 7 bytes" } */
      95    T (0, "%#ho",  R ( 0,  1));   /* { dg-warning "between 1 and 2 bytes" } */
      96    T (0, "%#ho",  R ( 1,  2));   /* { dg-warning "writing 2 bytes" } */
      97  
      98    T (0, "%#o",   i);            /* { dg-warning "between 1 and 12 bytes" } */
      99    T (0, "%#o",   R (-1,  0));   /* { dg-warning "between 1 and 12 bytes" } */
     100    T (0, "%#o",   R (-1,  1));   /* { dg-warning "between 1 and 12 bytes" } */
     101    T (0, "%#o",   R ( 0,  1));   /* { dg-warning "between 1 and 2 bytes" } */
     102    T (0, "%#o",   R ( 1,  2));   /* { dg-warning "writing 2 bytes" } */
     103  
     104    T (0, "%#hhx", i);            /* { dg-warning "between 1 and 4 bytes" } */
     105    T (0, "%#.*hhx",              /* { dg-warning "writing up to 4 bytes" } */
     106       R (0, 2), i);
     107    T (0, "%#.*hhx",              /* { dg-warning "between 1 and 4 bytes" } */
     108       R (1, 2), i);
     109    T (0, "%#.*hhx",              /* { dg-warning "between 2 and 5 bytes" } */
     110       R (2, 3), i);
     111    T (0, "%#.*hhx",              /* { dg-warning "between 3 and 6 bytes" } */
     112       R (3, 4), i);
     113  
     114    T (0, "%#hhx", R (-1,  0));   /* { dg-warning "between 1 and 4 bytes" } */
     115    T (0, "%#hhx", R (-1,  1));   /* { dg-warning "between 1 and 4 bytes" } */
     116    T (0, "%#hhx", R ( 0,  1));   /* { dg-warning "between 1 and 3 bytes" } */
     117    T (0, "%#hhx", R ( 1,  2));   /* { dg-warning "writing 3 bytes" } */
     118  
     119    T (0, "%#hx", i);             /* { dg-warning "between 1 and 6 bytes" } */
     120    T (0, "%#hx", R (-1,  0));    /* { dg-warning "between 1 and 6 bytes" } */
     121    T (0, "%#hx", R (-1,  1));    /* { dg-warning "between 1 and 6 bytes" } */
     122    T (0, "%#hx", R ( 0,  1));    /* { dg-warning "between 1 and 3 bytes" } */
     123    T (0, "%#hx", R ( 1,  2));    /* { dg-warning "writing 3 bytes" } */
     124  
     125    T (0, "%#x",   i);            /* { dg-warning "between 1 and 10 bytes" } */
     126    T (0, "%#x",   R (-1,  0));   /* { dg-warning "between 1 and 10 bytes" } */
     127    T (0, "%#x",   R (-1,  1));   /* { dg-warning "between 1 and 10 bytes" } */
     128    T (0, "%#x",   R ( 0,  1));   /* { dg-warning "between 1 and 3 bytes" } */
     129    T (0, "%#x",   R ( 1,  2));   /* { dg-warning "writing 3 bytes" } */
     130  }
     131  
     132  /* Verify warnings and ranges for likely overflow.  */
     133  void test_likely_overflow (int i)
     134  {
     135    T (2, "%#hho", i);          /* { dg-warning "may write a terminating nul" } */
     136    T (2, "%#1hho", i);         /* { dg-warning "may write a terminating nul" } */
     137    T (2, "%#2hho", i);         /* { dg-warning "writing a terminating nul" } */
     138    T (2, "%#3hho", i);         /* { dg-warning "between 3 and 4 bytes" } */
     139    T (2, "%#4hho", i);         /* { dg-warning "writing 4 bytes" } */
     140    T (2, "%#hho", R (-1,  0)); /* { dg-warning "may write a terminating nul" } */
     141    T (2, "%#1hho", R (-1,  0));/* { dg-warning "may write a terminating nul" } */
     142    T (2, "%#2hho", R (-1,  0));/* { dg-warning "writing a terminating nul" } */
     143    T (2, "%#3hho", R (-1,  0));/* { dg-warning "between 3 and 4 bytes" } */
     144    T (2, "%#4hho", R (-1,  0));/* { dg-warning "writing 4 bytes" } */
     145    T (2, "%#hho", R (-1,  1)); /* { dg-warning "may write a terminating nul" } */
     146    T (2, "%#1hho", R (-1,  1));/* { dg-warning "may write a terminating nul" } */
     147    T (2, "%#2hho", R (-1,  1));/* { dg-warning "writing a terminating nul" } */
     148    T (2, "%#3hho", R (-1,  1));/* { dg-warning "between 3 and 4 bytes" } */
     149    T (2, "%#4hho", R (-1,  1));/* { dg-warning "writing 4 bytes" } */
     150    T (2, "%#hho", R ( 0,  1)); /* { dg-warning "may write a terminating nul" } */
     151    T (2, "%#1hho", R ( 0,  1));/* { dg-warning "may write a terminating nul" } */
     152    T (2, "%#2hho", R ( 0,  1));/* { dg-warning "writing a terminating nul" } */
     153    T (2, "%#3hho", R ( 0,  1));/* { dg-warning "writing 3 bytes" } */
     154    T (2, "%#4hho", R ( 0,  1));/* { dg-warning "writing 4 bytes" } */
     155    T (2, "%#hho", R ( 1,  2)); /* { dg-warning "writing a terminating nul" } */
     156    T (2, "%#1hho", R ( 1,  2));/* { dg-warning "writing a terminating nul" } */
     157    T (2, "%#2hho", R ( 1,  2));/* { dg-warning "writing a terminating nul" } */
     158    T (2, "%#3hho", R ( 1,  2));/* { dg-warning "writing 3 bytes" } */
     159    T (2, "%#4hho", R ( 1,  2));/* { dg-warning "writing 4 bytes" } */
     160  
     161    T (2, "%#ho",  i);          /* { dg-warning "may write a terminating nul" } */
     162    T (2, "%#ho",  R (-1,  0)); /* { dg-warning "may write a terminating nul" } */
     163    T (2, "%#ho",  R (-1,  1)); /* { dg-warning "may write a terminating nul" } */
     164    T (2, "%#ho",  R ( 0,  1)); /* { dg-warning "may write a terminating nul" } */
     165    T (2, "%#ho",  R ( 1,  2)); /* { dg-warning "writing a terminating nul" } */
     166  
     167    T (2, "%#o",   i);          /* { dg-warning "may write a terminating nul" } */
     168    T (2, "%#o",   R (-1,  0)); /* { dg-warning "may write a terminating nul" } */
     169    T (2, "%#o",   R (-1,  1)); /* { dg-warning "may write a terminating nul" } */
     170    T (2, "%#o",   R ( 0,  1)); /* { dg-warning "may write a terminating nul" } */
     171    T (2, "%#o",   R ( 1,  2)); /* { dg-warning "writing a terminating nul" } */
     172  
     173    T (2, "%#hhx", i);          /* { dg-warning "between 1 and 4 bytes" } */
     174    T (2, "%#1hhx", i);         /* { dg-warning "between 1 and 4 bytes" } */
     175    T (2, "%#2hhx", i);         /* { dg-warning "between 2 and 4 bytes" } */
     176    T (2, "%#3hhx", i);         /* { dg-warning "between 3 and 4 bytes" } */
     177    T (2, "%#4hhx", i);         /* { dg-warning "writing 4 bytes" } */
     178    T (2, "%#1hhx", R (-1,  0));/* { dg-warning "between 1 and 4 bytes" } */
     179    T (2, "%#2hhx", R (-1,  0));/* { dg-warning "between 2 and 4 bytes" } */
     180    T (2, "%#3hhx", R (-1,  0));/* { dg-warning "between 3 and 4 bytes" } */
     181    T (2, "%#4hhx", R (-1,  0));/* { dg-warning "writing 4 bytes" } */
     182    T (2, "%#hhx", R (-1,  0)); /* { dg-warning "between 1 and 4 bytes" } */
     183    T (2, "%#1hhx", R (-1,  0));/* { dg-warning "between 1 and 4 bytes" } */
     184    T (2, "%#2hhx", R (-1,  0));/* { dg-warning "between 2 and 4 bytes" } */
     185    T (2, "%#3hhx", R (-1,  0));/* { dg-warning "between 3 and 4 bytes" } */
     186    T (2, "%#4hhx", R (-1,  0));/* { dg-warning "writing 4 bytes" } */
     187    T (2, "%#hhx", R (-1,  1)); /* { dg-warning "between 1 and 4 bytes" } */
     188    T (2, "%#1hhx", R (-1,  1));/* { dg-warning "between 1 and 4 bytes" } */
     189    T (2, "%#2hhx", R (-1,  1));/* { dg-warning "between 2 and 4 bytes" } */
     190    T (2, "%#3hhx", R (-1,  1));/* { dg-warning "between 3 and 4 bytes" } */
     191    T (2, "%#4hhx", R (-1,  1));/* { dg-warning "writing 4 bytes" } */
     192    T (2, "%#hhx", R ( 0,  1)); /* { dg-warning "between 1 and 3 bytes" } */
     193    T (2, "%#1hhx", R ( 0,  1));/* { dg-warning "between 1 and 3 bytes" } */
     194    T (2, "%#2hhx", R ( 0,  1));/* { dg-warning "between 2 and 3 bytes" } */
     195    T (2, "%#3hhx", R ( 0,  1));/* { dg-warning "writing 3 bytes" } */
     196    T (2, "%#4hhx", R ( 0,  1));/* { dg-warning "writing 4 bytes" } */
     197    T (2, "%#hhx", R ( 1,  2)); /* { dg-warning "writing 3 bytes" } */
     198    T (2, "%#1hhx", R ( 1,  2));/* { dg-warning "writing 3 bytes" } */
     199    T (2, "%#2hhx", R ( 1,  2));/* { dg-warning "writing 3 bytes" } */
     200    T (2, "%#3hhx", R ( 1,  2));/* { dg-warning "writing 3 bytes" } */
     201    T (2, "%#4hhx", R ( 1,  2));/* { dg-warning "writing 4 bytes" } */
     202  
     203    T (2, "%#hx", i);           /* { dg-warning "between 1 and 6 bytes" } */
     204    T (2, "%#hx", R (-1,  0));  /* { dg-warning "between 1 and 6 bytes" } */
     205    T (2, "%#hx", R (-1,  1));  /* { dg-warning "between 1 and 6 bytes" } */
     206    T (2, "%#hx", R ( 0,  1));  /* { dg-warning "between 1 and 3 bytes" } */
     207    T (2, "%#hx", R ( 1,  2));  /* { dg-warning "writing 3 bytes" } */
     208  
     209    T (2, "%#x",   i);          /* { dg-warning "between 1 and 10 bytes" } */
     210    T (2, "%#x",   R (-1,  0)); /* { dg-warning "between 1 and 10 bytes" } */
     211    T (2, "%#x",   R (-1,  1)); /* { dg-warning "between 1 and 10 bytes" } */
     212    T (2, "%#x",   R ( 0,  1)); /* { dg-warning "between 1 and 3 bytes" } */
     213    T (2, "%#x",   R ( 1,  2)); /* { dg-warning "writing 3 bytes" } */
     214  }
     215  
     216  /* Verify warnings likely overflow due to the terminating nul.  */
     217  void test_likely_nul_overflow (int i)
     218  {
     219    T (3, "%#hho", i);
     220    T (3, "%#hho", R (-1,  0));
     221    T (3, "%#hho", R (-1,  1));
     222    T (3, "%#hho", R ( 0,  1));
     223    T (3, "%#hho", R ( 1,  2));
     224  
     225    T (3, "%#ho",  i);
     226    T (3, "%#ho",  R (-1,  0));
     227    T (3, "%#ho",  R (-1,  1));
     228    T (3, "%#ho",  R ( 0,  1));
     229    T (3, "%#ho",  R ( 1,  2));
     230  
     231    T (3, "%#o",   i);
     232    T (3, "%#o",   R (-1,  0));
     233    T (3, "%#o",   R (-1,  1));
     234    T (3, "%#o",   R ( 0,  1));
     235    T (3, "%#o",   R ( 1,  2));
     236  
     237    T (3, "%#hhx", i);          /* { dg-warning "may write a terminating nul" } */
     238    T (3, "%#hhx", R (-1,  0)); /* { dg-warning "may write a terminating nul" } */
     239    T (3, "%#hhx", R (-1,  1)); /* { dg-warning "may write a terminating nul" } */
     240    T (3, "%#hhx", R ( 0,  1)); /* { dg-warning "may write a terminating nul" } */
     241    T (3, "%#hhx", R ( 1,  2)); /* { dg-warning "writing a terminating nul" } */
     242  
     243    T (3, "%#hx", i);           /* { dg-warning "may write a terminating nul" } */
     244    T (3, "%#hx", R (-1,  0));  /* { dg-warning "may write a terminating nul" } */
     245    T (3, "%#hx", R (-1,  1));  /* { dg-warning "may write a terminating nul" } */
     246    T (3, "%#hx", R ( 0,  1));  /* { dg-warning "may write a terminating nul" } */
     247    T (3, "%#hx", R ( 1,  2));  /* { dg-warning "writing a terminating nul" } */
     248  
     249    T (3, "%#x",   i);          /* { dg-warning "may write a terminating nul" } */
     250    T (3, "%#x",   R (-1,  0)); /* { dg-warning "may write a terminating nul" } */
     251    T (3, "%#x",   R (-1,  1)); /* { dg-warning "may write a terminating nul" } */
     252    T (3, "%#x",   R ( 0,  1)); /* { dg-warning "may write a terminating nul" } */
     253    T (3, "%#x",   R ( 1,  2)); /* { dg-warning "writing a terminating nul" } */
     254  }