1  /* PR tree-optimization/77671 - missing -Wformat-overflow warning
       2     on sprintf overflow with "%s"
       3  
       4     Negative test verifying that sprintf family calls that must not
       5     be transformed into calls to other functions (such as memcpy)
       6     are preserved.
       7  
       8     { dg-compile }
       9     { dg-options "-O2 -Wformat -Wno-format-truncation -Wno-format-zero-length -fdump-tree-optimized" } */
      10  
      11  void sink (char*, ...);
      12  
      13  extern char buffer[];
      14  
      15  /* String exactly 4100 characters long (plus the terminating NUL).  */
      16  extern const char s4100[4101];
      17  
      18  void test_sprintf (const char *s)
      19  {
      20    /* Macros to test the function call while eignoring and using
      21       the return value, respectively.  */
      22  #define IGN(...) __builtin_sprintf (buffer, __VA_ARGS__), sink (buffer)
      23  #define USE(...) sink (buffer, __builtin_sprintf (buffer, __VA_ARGS__))
      24  
      25    /* All of the following calls to sprintf must be emitted (and not
      26       transformed into memcpy, strcpy, or similar).  */
      27  
      28    /* Verify that a sprintf call with output in excess of the maximum
      29       of 4095 bytes is not transformed into memcpy/strcpy when its
      30       return value is used (the call may fail with EOVERFLOW but
      31       the error is only detectable when the function's negative return
      32       value indicates errno is valid ).  */
      33    USE (s4100);
      34  
      35    USE ("%s", s4100);
      36  
      37    /* Same as above but with string of unknown length (which could
      38       be in excess of 4K long).  */
      39    USE (s);
      40    USE ("%s", s);
      41  }
      42  
      43  
      44  void test_snprintf (void)
      45  {
      46  #undef IGN
      47  #define IGN(N, ...) __builtin_snprintf (buffer, N, __VA_ARGS__); sink (buffer)
      48  
      49    /* All of the following calls to sprintf must be emitted (and not
      50       transformed into memcpy, strcpy, or similar).  */
      51  
      52    /* Truncated output could be optimized into strncpy (not done yet).  */
      53    IGN (1, "123");
      54    IGN (1, s4100);
      55  
      56    IGN (1, "%s", "123");
      57    IGN (1, "%s", s4100);
      58  
      59    /* Output in excess of the maximum of 4095 bytes.  */
      60    IGN (4097, s4100);
      61  
      62    IGN (4097, "%s", s4100);
      63  }
      64  
      65  
      66  void test_vsprintf (__builtin_va_list va)
      67  {
      68  #undef IGN
      69  #define IGN(fmt) __builtin_vsprintf (buffer, fmt, va); sink (buffer)
      70  
      71    /* All of the following calls to vsprintf must be emitted (and not
      72       transformed into memcpy, strcpy, or similar).  */
      73  
      74    /* Output in excess of the maximum of 4095 bytes.  */
      75    IGN (s4100);
      76  }
      77  
      78  
      79  void test_vsnprintf (__builtin_va_list va)
      80  {
      81  #undef IGN
      82  #define IGN(N, fmt) __builtin_vsnprintf (buffer, N, fmt, va); sink (buffer)
      83  
      84    /* All of the following calls to vsnprintf must be emitted (and not
      85       transformed into memcpy, strcpy, or similar).  */
      86  
      87    /* Truncated output could be optimized into strncpy (not done yet).  */
      88    IGN (1, "123");
      89    IGN (1, s4100);
      90  
      91    /* Output in excess of the maximum of 4095 bytes.  */
      92    IGN (4097, s4100);
      93  }
      94  
      95  /* { dg-final { scan-tree-dump-times "builtin_sprintf" 4 "optimized" } }
      96     { dg-final { scan-tree-dump-times "builtin_snprintf" 6 "optimized" } }
      97     { dg-final { scan-tree-dump-times "builtin_vsprintf" 1 "optimized" } }
      98     { dg-final { scan-tree-dump-times "builtin_vsnprintf" 3 "optimized" } } */
      99  
     100  #define S10    "0123456789"
     101  #define S100   S10 S10 S10 S10 S10  S10 S10 S10 S10 S10
     102  #define S1000  S100 S100 S100 S100 S100  S100 S100 S100 S100 S100
     103  
     104  const char s4100[4101] = S1000 S1000 S1000 S1000 S100;