]>
Commit | Line | Data |
---|---|---|
3e6837c2 MS |
1 | /* PR tree-optimization/87096 - "Optimised" snprintf is not POSIX conformant |
2 | Verify that calls to snprintf with size in excess of INT_MAX are not | |
3 | treated as successful. | |
4 | It would be valid for GCC to fold some of these calls to a negative | |
5 | value provided it also arranged to set errno to EOVERFLOW. If that | |
6 | is ever implemented this test will need to be adjusted. | |
7 | { dg-do compile } | |
8 | { dg-options "-O2 -Wall -fdump-tree-optimized -ftrack-macro-expansion=0" } */ | |
9 | ||
10 | #include "../range.h" | |
11 | ||
12 | typedef __builtin_va_list va_list; | |
13 | ||
14 | extern int snprintf (char*, size_t, const char*, ...); | |
15 | extern int vsnprintf (char*, size_t, const char*, va_list); | |
16 | ||
17 | #define CAT(x, y) x ## y | |
18 | #define CONCAT(x, y) CAT (x, y) | |
19 | #define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__) | |
20 | ||
21 | #define FAIL(name) do { \ | |
22 | extern void FAILNAME (name) (void); \ | |
23 | FAILNAME (name)(); \ | |
24 | } while (0) | |
25 | ||
26 | /* Macro to emit a call to function named | |
27 | call_in_true_branch_not_eliminated_on_line_NNN() | |
28 | for each expression that's expected to fold to false but that | |
29 | GCC does not fold. The dg-final scan-tree-dump-time directive | |
30 | at the bottom of the test verifies that no such call appears | |
31 | in output. */ | |
32 | #define ELIM(expr) \ | |
33 | if ((expr)) FAIL (in_true_branch_not_eliminated); else (void)0 | |
34 | ||
35 | /* Macro to emit a call to a function named | |
36 | call_made_in_{true,false}_branch_on_line_NNN() | |
37 | for each call that's expected to be retained. The dg-final | |
38 | scan-tree-dump-time directive at the bottom of the test verifies | |
39 | that the expected number of both kinds of calls appears in output | |
40 | (a pair for each line with the invocation of the KEEP() macro. */ | |
41 | #define KEEP(expr) \ | |
42 | if (expr) \ | |
43 | FAIL (made_in_true_branch); \ | |
44 | else \ | |
45 | FAIL (made_in_false_branch) | |
46 | ||
47 | extern void sink (int, ...); | |
48 | #define sink(...) sink (0, __VA_ARGS__) | |
49 | ||
50 | #define WARN(N, expr) \ | |
51 | do { \ | |
52 | char a[N]; \ | |
53 | expr; \ | |
54 | sink (a); \ | |
55 | } while (0) | |
56 | ||
57 | ||
58 | static const size_t imax = __INT_MAX__; | |
59 | static const size_t imaxp1 = imax + 1; | |
60 | ||
22b04f05 MS |
61 | #if __PTRDIFF_MAX__ == __INT_MAX__ |
62 | /* Make the test pass on ILP32 the same way it does on LP64. */ | |
63 | static const size_t dmax = __PTRDIFF_MAX__ + (size_t)1; | |
64 | #else | |
3e6837c2 | 65 | static const size_t dmax = __PTRDIFF_MAX__; |
22b04f05 | 66 | #endif |
3e6837c2 MS |
67 | static const size_t dmaxp1 = dmax + 1; |
68 | ||
69 | static const size_t szmax = __SIZE_MAX__; | |
70 | static const size_t szmaxm1 = __SIZE_MAX__ - 1; | |
71 | ||
72 | ||
73 | void test_size_cst (char **d) | |
74 | { | |
75 | ELIM (0 > snprintf (*d++, imax, "%s", "")); | |
76 | ||
77 | KEEP (0 > snprintf (*d++, imaxp1, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
78 | ||
79 | KEEP (0 > snprintf (*d++, dmax, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
80 | KEEP (0 > snprintf (*d++, dmaxp1, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
81 | KEEP (0 > snprintf (*d++, szmaxm1, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
82 | KEEP (0 > snprintf (*d++, szmax, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
83 | } | |
84 | ||
85 | ||
86 | void test_size_cst_va (char **d, va_list va) | |
87 | { | |
88 | ELIM (0 > vsnprintf (*d++, imax, " ", va)); | |
89 | ||
90 | KEEP (0 > vsnprintf (*d++, imaxp1, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
91 | ||
92 | KEEP (0 > vsnprintf (*d++, dmax, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
93 | KEEP (0 > vsnprintf (*d++, dmaxp1, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
94 | KEEP (0 > vsnprintf (*d++, szmaxm1, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
95 | KEEP (0 > vsnprintf (*d++, szmax, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
96 | } | |
97 | ||
98 | ||
99 | void test_size_range (char **d) | |
100 | { | |
101 | size_t r = UR (imax - 1, imax); | |
102 | ELIM (0 > snprintf (*d++, r, "%s", "")); | |
103 | ||
104 | r = UR (imax, imax + 1); | |
105 | KEEP (0 > snprintf (*d++, r, "%s", "")); | |
106 | ||
107 | r = UR (imaxp1, imaxp1 + 1); | |
108 | KEEP (0 > snprintf (*d++, r, "%s", "")); /* { dg-warning "specified bound range \\\[\[0-9\]+, \[0-9\]+] exceeds .INT_MAX." } */ | |
109 | ||
110 | r = UR (dmax, dmaxp1); | |
111 | KEEP (0 > snprintf (*d++, r, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
112 | ||
113 | r = UR (dmaxp1, dmaxp1 + 1); | |
114 | KEEP (0 > snprintf (*d++, r, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
115 | ||
116 | r = UR (szmaxm1, szmax); | |
117 | KEEP (0 > snprintf (*d++, r, "%s", "")); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
118 | } | |
119 | ||
120 | ||
121 | void test_size_range_va (char **d, va_list va) | |
122 | { | |
123 | size_t r = UR (imax - 1, imax); | |
124 | ELIM (0 > vsnprintf (*d++, r, " ", va)); | |
125 | ||
126 | r = UR (imax, imax + 1); | |
127 | KEEP (0 > vsnprintf (*d++, r, " ", va)); | |
128 | ||
129 | r = UR (imaxp1, imaxp1 + 1); | |
130 | KEEP (0 > vsnprintf (*d++, r, " ", va)); /* { dg-warning "specified bound range \\\[\[0-9\]+, \[0-9\]+] exceeds .INT_MAX." } */ | |
131 | ||
132 | r = UR (dmax, dmaxp1); | |
133 | KEEP (0 > vsnprintf (*d++, r, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
134 | ||
135 | r = UR (dmaxp1, dmaxp1 + 1); | |
136 | KEEP (0 > vsnprintf (*d++, r, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
137 | ||
138 | r = UR (szmaxm1, szmax); | |
139 | KEEP (0 > vsnprintf (*d++, r, " ", va)); /* { dg-warning "\\\[-Wformat-truncation=]" } */ | |
140 | } | |
141 | ||
142 | ||
143 | void test_size_varying (char **d, size_t n) | |
144 | { | |
145 | KEEP (0 > snprintf (*d++, n, "%s", "")); | |
146 | ||
147 | n += 1; | |
148 | KEEP (0 > snprintf (*d++, n, "%s", "")); | |
149 | } | |
150 | ||
151 | ||
152 | void test_size_varying_va (char **d, size_t n, va_list va) | |
153 | { | |
154 | KEEP (0 > vsnprintf (*d++, n, " ", va)); | |
155 | ||
156 | n += 1; | |
157 | KEEP (0 > vsnprintf (*d++, n, " ", va)); | |
158 | } | |
159 | ||
160 | /* { dg-final { scan-tree-dump-times " = snprintf" 12 "optimized"} } | |
161 | { dg-final { scan-tree-dump-times " = vsnprintf" 12 "optimized"} } */ |