1 /* { dg-do compile } */
2 /* { dg-options "-Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" } */
3 
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.  */
7 #ifndef LINE
8 # define LINE 0
9 #endif
10 
11 char buffer [256];
12 extern char *ptr;
13 
14 #define buffer(size)							\
15   (!LINE || __LINE__ == LINE ? buffer + sizeof buffer - size : ptr)
16 
17 #define objsize(size)  (!LINE || __LINE__ == LINE ? size : __SIZE_MAX__ / 2)
18 
19 typedef __SIZE_TYPE__ size_t;
20 
21 #if !__cplusplus
22 typedef __WCHAR_TYPE__ wchar_t;
23 #endif
24 
25 typedef unsigned char UChar;
26 
27 #define T(size, fmt, ...)				\
28   __builtin_sprintf (buffer (size), fmt, __VA_ARGS__)
29 
30 __builtin_va_list va;
31 
32 /* Exercise buffer overflow detection with const string arguments.  */
33 
test_s_const(void)34 void test_s_const (void)
35 {
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" } */
41   T (1, "%ls",      L"");
42   T (1, "%ls",      L"\0");
43   T (1, "%1ls",     L"");       /* { dg-warning "nul past the end" } */
44 
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" } */
49 
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" } */
54   T (1, "%.0ls",    L"1");
55   T (2, "%.0ls",    L"1");
56   T (2, "%.1ls",    L"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" } */
61 
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" } */
68 
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.  */
71   T (2, "%.0ls",    L"1");
72   T (2, "%.1ls",    L"1");
73   T (3, "%.2ls",    L"1");
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" } */
80 }
81 
82 
83 struct Arrays {
84   char a1 [1];
85   char a2 [2];
86   char a3 [3];
87   char a4 [4];
88   char a0 [0];
89   char ax [];
90 };
91 
92 /* Exercise buffer overflow detection with non-const string arguments.  */
93 
test_s_nonconst(int w,int p,const char * s,const wchar_t * ws,struct Arrays * a)94 void test_s_nonconst (int w, int p, const char *s, const wchar_t *ws,
95 		      struct Arrays *a)
96 {
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" } */
100   T (1, "%.0s", s);
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" } */
106 
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" } */
110 
111   T (1, "%.0ls",  ws);
112   T (1, "%.1ls",  ws);          /* { dg-warning "may write a terminating nul" } */
113   T (1, "%ls",    ws);          /* { dg-warning "may write a terminating nul" } */
114 
115   /* Verify that the size of the array is used in lieu of its length.  */
116   T (1, "%s", a->a1);
117 
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" } */
123 
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" } */
128 
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" } */
133 
134   T (2, "%s", a->a0);
135   T (2, "%s", a->ax);
136 }
137 
138   /* Exercise buffer overflow detection with non-const integer arguments.  */
139 
test_hh_nonconst(int w,int p,int x,unsigned y)140 void test_hh_nonconst (int w, int p, int x, unsigned y)
141 {
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" } */
146 
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" } */
151 
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" } */
157 
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" } */
164 
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" } */
169 
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" } */
175 
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" } */
181 
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" } */
187 
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 } */
195 }
196 
test_h_nonconst(int x)197 void test_h_nonconst (int x)
198 {
199   extern UChar uc;
200 
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" } */
206   T (4, "%hi",         uc);
207 
208   /* Verify that the same thing works when the int argument is cast
209      to unsigned char.  */
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);
214 }
215 
test_i_nonconst(int x)216 void test_i_nonconst (int x)
217 {
218   extern UChar uc;
219 
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" } */
223   T (4, "%i",          uc);
224 
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);
229 
230   /* Verify the same thing using a bit-field.  */
231   extern struct {
232     unsigned int  b1: 1;
233     unsigned int  b2: 2;
234     unsigned int  b3: 3;
235     unsigned int  b4: 4;
236 	     int sb4: 4;
237     unsigned int  b5: 5;
238     unsigned int  b6: 6;
239     unsigned int  b7: 7;
240     unsigned int  b8: 8;
241   } bf, abf[], *pbf;
242 
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
248      decimal digit.  */
249   T (2, "%i",       bf.b1);
250   T (2, "%i",  abf [x].b1);
251   T (2, "%i",     pbf->b1);
252   T (2, "%i",       bf.b2);
253   T (2, "%i",  abf [x].b2);
254   T (2, "%i",     pbf->b2);
255   T (2, "%i",       bf.b3);
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" } */
262 
263   T (3, "%i",       bf.b4);
264   T (3, "%i",     pbf->b4);
265   T (3, "%i",       bf.b5);
266   T (3, "%i",     pbf->b5);
267   T (3, "%i",       bf.b6);
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" } */
271 
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" } */
277   T (4, "%i",       bf.b8);
278 
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" } */
282 
283   T (2, "%i",      bf.sb4);     /* { dg-warning "terminating nul past" } */
284   T (3, "%i",      bf.sb4);
285   T (4, "%i",      bf.sb4);
286 }
287