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 
test_sprintf(const char * s)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 
test_snprintf(void)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 
test_vsprintf(__builtin_va_list va)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 
test_vsnprintf(__builtin_va_list va)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;
105