1 /* { dg-do compile } */
2 /* { dg-options "-Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" } */
4 /* When debugging, define LINE to the line number of the test case to exercise
5 and avoid exercising any of the others. The buffer and objsize macros
6 below make use of LINE to avoid warnings for other lines. */
14 #define buffer(size) \
15 (!LINE || __LINE__ == LINE ? buffer + sizeof buffer - size : ptr)
17 #define objsize(size) (!LINE || __LINE__ == LINE ? size : __SIZE_MAX__ / 2)
19 typedef __SIZE_TYPE__
size_t;
22 typedef __WCHAR_TYPE__
wchar_t;
25 typedef unsigned char UChar
;
27 #define T(size, fmt, ...) \
28 __builtin_sprintf (buffer (size), fmt, __VA_ARGS__)
32 /* Exercise buffer overflow detection with const string arguments. */
34 void test_s_const (void)
36 /* Wide string literals are handled slightly differently than
37 at level 1. At level 1, each wide character is assumed to
38 convert into a single byte. At level 2, they are assumed
39 to convert into at least one byte. */
40 T (0, "%ls", L
""); /* { dg-warning "nul past the end" } */
43 T (1, "%1ls", L
""); /* { dg-warning "nul past the end" } */
45 T (0, "%*ls", 0, L
""); /* { dg-warning "nul past the end" } */
46 T (1, "%*ls", 0, L
"");
47 T (1, "%*ls", 0, L
"\0");
48 T (1, "%*ls", 1, L
""); /* { dg-warning "nul past the end" } */
50 /* A wide character converts into between zero and MB_LEN_MAX bytes
51 (although individual ASCII characters are assumed to convert into
52 1 bt %lc so this could be made smarter. */
53 T (1, "%ls", L
"1"); /* { dg-warning "directive writing up to 6 bytes into a region of size 1" } */
57 T (2, "%.2ls", L
"1"); /* { dg-warning "nul past the end" } */
58 T (2, "%.3ls", L
"1"); /* { dg-warning "directive writing up to 3 bytes into a region of size 2" } */
59 T (2, "%.7ls", L
"1"); /* { dg-warning "directive writing up to 6 bytes into a region of size 2" } */
60 T (2, "%.2ls", L
"12"); /* { dg-warning "nul past the end" } */
62 /* The "%.2ls" directive below will write at a minimum 1 byte (because
63 L"1" is known and can be assumed to convert to at least one multibyte
64 character), and at most 2 bytes because of the precision. Since its
65 output is explicitly bounded it is diagnosed. */
66 T (2, "%.2ls", L
"1"); /* { dg-warning "nul past the end" } */
67 T (2, "%.*ls", 2, L
"1"); /* { dg-warning "nul past the end" } */
69 /* The following three are constrained by the precision to at most
70 that many bytes of the converted wide string plus a terminating NUL. */
74 T (3, "%.2ls", L
"12");
75 T (3, "%.3ls", L
"12"); /* { dg-warning "nul past the end" } */
76 T (4, "%.3ls", L
"123");
77 T (4, "%.4ls", L
"123"); /* { dg-warning "nul past the end" } */
78 T (4, "%.5ls", L
"123"); /* { dg-warning "directive writing up to 5 bytes into a region of size 4" } */
79 T (4, "%.6ls", L
"123"); /* { dg-warning "directive writing up to 6 bytes into a region of size 4" } */
92 /* Exercise buffer overflow detection with non-const string arguments. */
94 void test_s_nonconst (int w
, int p
, const char *s
, const wchar_t *ws
,
97 T (0, "%s", s
); /* { dg-warning "into a region" } */
98 T (1, "%s", s
); /* { dg-warning "nul past the end" } */
99 T (1, "%1s", s
); /* { dg-warning "writing a terminating nul" } */
101 T (1, "%.1s", s
); /* { dg-warning "may write a terminating nul" } */
102 T (1, "%*s", 0, s
); /* { dg-warning "may write a terminating nul" } */
103 T (1, "%*s", 1, s
); /* { dg-warning "writing a terminating nul" } */
104 T (1, "%*s", 2, s
); /* { dg-warning "directive writing 2 or more bytes" } */
105 T (1, "%*s", 3, s
); /* { dg-warning "directive writing 3 or more bytes" } */
107 T (1, "%.*s", 1, s
); /* { dg-warning "may write a terminating nul" } */
108 T (1, "%.*s", 2, s
); /* { dg-warning "writing up to 2 bytes" } */
109 T (1, "%.*s", 3, s
); /* { dg-warning "writing up to 3 bytes" } */
112 T (1, "%.1ls", ws
); /* { dg-warning "may write a terminating nul" } */
113 T (1, "%ls", ws
); /* { dg-warning "may write a terminating nul" } */
115 /* Verify that the size of the array is used in lieu of its length. */
118 /* In the following test, since the length of the strings isn't known,
119 their type (the array) is used to bound the maximum length to 1,
120 which means the "%s" directive would not overflow the buffer,
121 but it would leave no room for the terminating nul. */
122 T (1, "%s", a
->a2
); /* { dg-warning "may write a terminating nul" } */
124 /* Unlike in the test above, since the length of the string is bounded
125 by the array type to at most 2, the "%s" directive is diagnosed firts,
126 preventing the diagnostic about the terminatinb nul. */
127 T (1, "%s", a
->a3
); /* { dg-warning "directive writing up to 2 bytes" } */
129 /* The length of a zero length array and flexible array member is
130 unknown and at leve 2 assumed to be at least 1. */
131 T (1, "%s", a
->a0
); /* { dg-warning "may write a terminating nul" } */
132 T (1, "%s", a
->ax
); /* { dg-warning "may write a terminating nul" } */
138 /* Exercise buffer overflow detection with non-const integer arguments. */
140 void test_hh_nonconst (int w
, int p
, int x
, unsigned y
)
142 T (1, "%hhi", x
); /* { dg-warning "into a region" } */
143 T (2, "%hhi", x
); /* { dg-warning "into a region" } */
144 T (3, "%hhi", x
); /* { dg-warning "into a region" } */
145 T (4, "%hhi", x
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
147 T (1, "%hhi", y
); /* { dg-warning "between 1 and 4 bytes" } */
148 T (2, "%hhi", y
); /* { dg-warning "into a region" } */
149 T (3, "%hhi", y
); /* { dg-warning "into a region" } */
150 T (4, "%hhi", y
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
152 /* Negative precision is treated as if none were specified. */
153 T (1, "%.*hhi", -1, x
); /* { dg-warning "between 1 and 4 bytes" } */
154 T (2, "%.*hhi", -1, x
); /* { dg-warning "into a region" } */
155 T (3, "%.*hhi", -1, x
); /* { dg-warning "into a region" } */
156 T (4, "%.*hhi", -1, x
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
158 /* Zero precision means that zero argument formats as no bytes unless
159 length or flags make it otherwise. */
160 T (1, "%.*hhi", 0, x
); /* { dg-warning "writing up to 4 bytes" } */
161 T (2, "%.*hhi", 0, x
); /* { dg-warning "writing up to 4 bytes" } */
162 T (3, "%.*hhi", 0, x
); /* { dg-warning "writing up to 4 bytes" } */
163 T (4, "%.*hhi", 0, x
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
165 T (1, "%.*hhi", 0, y
); /* { dg-warning "writing up to 4 bytes" } */
166 T (2, "%.*hhi", 0, y
); /* { dg-warning "writing up to 4 bytes" } */
167 T (3, "%.*hhi", 0, y
); /* { dg-warning "writing up to 4 bytes" } */
168 T (4, "%.*hhi", 0, y
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
170 T (1, "%#.*hhi", 0, y
); /* { dg-warning "writing up to 4 bytes" } */
171 /* { dg-warning ".#. flag used" "-Wformat" { target *-*-* } .-1 } */
172 T (1, "%+.*hhi", 0, y
); /* { dg-warning "between 1 and 4 bytes" } */
173 T (1, "%-.*hhi", 0, y
); /* { dg-warning "writing up to 4 bytes" } */
174 T (1, "% .*hhi", 0, y
); /* { dg-warning "between 1 and 4 bytes" } */
176 T (1, "%#.*hhi", 1, y
); /* { dg-warning "between 1 and 4 bytes" } */
177 /* { dg-warning ".#. flag used" "-Wformat" { target *-*-* } .-1 } */
178 T (1, "%+.*hhi", 1, y
); /* { dg-warning "between 2 and 4 bytes" } */
179 T (1, "%-.*hhi", 1, y
); /* { dg-warning "between 1 and 4 bytes" } */
180 T (1, "% .*hhi", 1, y
); /* { dg-warning "between 2 and 4 bytes" } */
182 T (1, "%#.*hhi", p
, y
); /* { dg-warning "writing up to \[0-9\]+ bytes" } */
183 /* { dg-warning ".#. flag used" "-Wformat" { target *-*-* } .-1 } */
184 T (1, "%+.*hhi", p
, y
); /* { dg-warning "writing 1 or more bytes|writing between 1 and \[0-9\]+ bytes" } */
185 T (1, "%-.*hhi", p
, y
); /* { dg-warning "writing up to \[0-9\]+ bytes" } */
186 T (1, "% .*hhi", p
, y
); /* { dg-warning "writing between 1 and \[0-9\]+ bytes|writing 1 or more bytes" } */
188 T (1, "%#.*hhu", 0, y
); /* { dg-warning "writing up to 3 bytes" } */
189 /* { dg-warning ".#. flag used" "-Wformat" { target *-*-* } .-1 } */
190 T (1, "%+.*hhu", 0, y
); /* { dg-warning "writing up to 3 bytes" } */
191 /* { dg-warning ".\\+. flag used" "-Wformat" { target *-*-* } .-1 } */
192 T (1, "%-.*hhu", 0, y
); /* { dg-warning "writing up to 3 bytes" } */
193 T (1, "% .*hhu", 0, y
); /* { dg-warning "writing up to 3 bytes" } */
194 /* { dg-warning ". . flag used" "-Wformat" { target *-*-* } .-1 } */
197 void test_h_nonconst (int x
)
201 T (1, "%hi", uc
); /* { dg-warning "into a region" } */
202 T (2, "%hi", uc
); /* { dg-warning "into a region" } */
203 /* Formatting an 8-bit unsigned char as a signed short (or any other
204 type with greater precision) can write at most 3 characters. */
205 T (3, "%hi", uc
); /* { dg-warning "terminating nul past" } */
208 /* Verify that the same thing works when the int argument is cast
210 T (1, "%hi", (UChar
)x
); /* { dg-warning "into a region" } */
211 T (2, "%hi", (UChar
)x
); /* { dg-warning "into a region" } */
212 T (3, "%hi", (UChar
)x
); /* { dg-warning "may write a terminating nul past the end of the destination" } */
213 T (4, "%hi", (UChar
)x
);
216 void test_i_nonconst (int x
)
220 T (1, "%i", uc
); /* { dg-warning "into a region" } */
221 T (2, "%i", uc
); /* { dg-warning "into a region" } */
222 T (3, "%i", uc
); /* { dg-warning "terminating nul past" } */
225 T (1, "%i", (UChar
)x
); /* { dg-warning "into a region" } */
226 T (2, "%i", (UChar
)x
); /* { dg-warning "into a region" } */
227 T (3, "%i", (UChar
)x
); /* { dg-warning "terminating nul past" } */
228 T (4, "%i", (UChar
)x
);
230 /* Verify the same thing using a bit-field. */
243 T (1, "%i", bf
.b1
); /* { dg-warning "nul past the end" } */
244 T (1, "%i", abf
[x
].b1
); /* { dg-warning "nul past the end" } */
245 T (1, "%i", pbf
->b1
); /* { dg-warning "nul past the end" } */
246 /* A one bit bit-field can only be formatted as '0' or '1'. Similarly,
247 two- and three-bit bit-fields can only be formatted as a single
250 T (2, "%i", abf
[x
].b1
);
251 T (2, "%i", pbf
->b1
);
253 T (2, "%i", abf
[x
].b2
);
254 T (2, "%i", pbf
->b2
);
256 T (2, "%i", abf
[x
].b3
);
257 T (2, "%i", pbf
->b3
);
258 /* A four-bit bit-field can be formatted as either one or two digits. */
259 T (2, "%i", bf
.b4
); /* { dg-warning "nul past the end" } */
260 T (2, "%i", abf
[x
].b4
); /* { dg-warning "nul past the end" } */
261 T (2, "%i", pbf
->b4
); /* { dg-warning "nul past the end" } */
264 T (3, "%i", pbf
->b4
);
266 T (3, "%i", pbf
->b5
);
268 T (3, "%i", pbf
->b6
);
269 T (3, "%i", bf
.b7
); /* { dg-warning "nul past the end" } */
270 T (3, "%i", pbf
->b7
); /* { dg-warning "nul past the end" } */
272 T (1, "%i", bf
.b8
); /* { dg-warning "into a region" } */
273 T (2, "%i", bf
.b8
); /* { dg-warning "into a region" } */
274 /* Formatting an 8-bit unsigned char as a signed short (or any other
275 type with greater precision) int can write at most 3 characters. */
276 T (3, "%i", bf
.b8
); /* { dg-warning "terminating nul past" } */
279 T (1, "%i", bf
.b8
); /* { dg-warning "into a region" } */
280 T (2, "%i", bf
.b8
); /* { dg-warning "into a region" } */
281 T (3, "%i", bf
.b8
); /* { dg-warning "terminating nul past" } */
283 T (2, "%i", bf
.sb4
); /* { dg-warning "terminating nul past" } */