1 | /* Copyright (C) 1991-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #ifdef BSD |
19 | #include </usr/include/stdio.h> |
20 | #define EXIT_SUCCESS 0 |
21 | #else |
22 | #include <limits.h> |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #endif |
27 | |
28 | #include <float.h> |
29 | #include <libc-diag.h> |
30 | |
31 | /* This whole file is picayune tests of corner cases of printf format strings. |
32 | The compiler warnings are not useful here. */ |
33 | DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat" ); |
34 | |
35 | #if __GNUC_PREREQ (7, 0) |
36 | /* Compiler warnings about snprintf output truncation should also be |
37 | ignored. */ |
38 | DIAG_IGNORE_NEEDS_COMMENT (7.0, "-Wformat-truncation" ); |
39 | #endif |
40 | |
41 | static void rfg1 (void); |
42 | static void rfg2 (void); |
43 | static void rfg3 (void); |
44 | |
45 | |
46 | static void |
47 | fmtchk (const char *fmt) |
48 | { |
49 | (void) fputs(fmt, stdout); |
50 | (void) printf(format: ":\t`" ); |
51 | (void) printf(format: fmt, 0x12); |
52 | (void) printf(format: "'\n" ); |
53 | } |
54 | |
55 | static void |
56 | fmtst1chk (const char *fmt) |
57 | { |
58 | (void) fputs(fmt, stdout); |
59 | (void) printf(format: ":\t`" ); |
60 | (void) printf(format: fmt, 4, 0x12); |
61 | (void) printf(format: "'\n" ); |
62 | } |
63 | |
64 | static void |
65 | fmtst2chk (const char *fmt) |
66 | { |
67 | (void) fputs(fmt, stdout); |
68 | (void) printf(format: ":\t`" ); |
69 | (void) printf(format: fmt, 4, 4, 0x12); |
70 | (void) printf(format: "'\n" ); |
71 | } |
72 | |
73 | static int |
74 | do_test (void) |
75 | { |
76 | static char shortstr[] = "Hi, Z." ; |
77 | static char longstr[] = "Good morning, Doctor Chandra. This is Hal. \ |
78 | I am ready for my first lesson today." ; |
79 | int result = 0; |
80 | |
81 | fmtchk(fmt: "%.4x" ); |
82 | fmtchk(fmt: "%04x" ); |
83 | fmtchk(fmt: "%4.4x" ); |
84 | fmtchk(fmt: "%04.4x" ); |
85 | fmtchk(fmt: "%4.3x" ); |
86 | fmtchk(fmt: "%04.3x" ); |
87 | |
88 | fmtst1chk(fmt: "%.*x" ); |
89 | fmtst1chk(fmt: "%0*x" ); |
90 | fmtst2chk(fmt: "%*.*x" ); |
91 | fmtst2chk(fmt: "%0*.*x" ); |
92 | |
93 | #ifndef BSD |
94 | printf(format: "bad format:\t\"%v\"\n" ); |
95 | printf(format: "nil pointer (padded):\t\"%10p\"\n" , (void *) NULL); |
96 | #endif |
97 | |
98 | printf(format: "decimal negative:\t\"%d\"\n" , -2345); |
99 | printf(format: "octal negative:\t\"%o\"\n" , -2345); |
100 | printf(format: "hex negative:\t\"%x\"\n" , -2345); |
101 | printf(format: "long decimal number:\t\"%ld\"\n" , -123456L); |
102 | printf(format: "long octal negative:\t\"%lo\"\n" , -2345L); |
103 | printf(format: "long unsigned decimal number:\t\"%lu\"\n" , -123456L); |
104 | printf(format: "zero-padded LDN:\t\"%010ld\"\n" , -123456L); |
105 | printf(format: "left-adjusted ZLDN:\t\"%-010ld\"\n" , -123456L); |
106 | printf(format: "space-padded LDN:\t\"%10ld\"\n" , -123456L); |
107 | printf(format: "left-adjusted SLDN:\t\"%-10ld\"\n" , -123456L); |
108 | |
109 | printf(format: "zero-padded string:\t\"%010s\"\n" , shortstr); |
110 | printf(format: "left-adjusted Z string:\t\"%-010s\"\n" , shortstr); |
111 | printf(format: "space-padded string:\t\"%10s\"\n" , shortstr); |
112 | printf(format: "left-adjusted S string:\t\"%-10s\"\n" , shortstr); |
113 | /* GCC 9 warns about the NULL format argument; this is deliberately |
114 | tested here. */ |
115 | DIAG_PUSH_NEEDS_COMMENT; |
116 | #if __GNUC_PREREQ (7, 0) |
117 | DIAG_IGNORE_NEEDS_COMMENT (9, "-Wformat-overflow=" ); |
118 | #endif |
119 | printf(format: "null string:\t\"%s\"\n" , (char *)NULL); |
120 | DIAG_POP_NEEDS_COMMENT; |
121 | printf(format: "limited string:\t\"%.22s\"\n" , longstr); |
122 | |
123 | printf(format: "a-style max:\t\"%a\"\n" , DBL_MAX); |
124 | printf(format: "a-style -max:\t\"%a\"\n" , -DBL_MAX); |
125 | printf(format: "e-style >= 1:\t\"%e\"\n" , 12.34); |
126 | printf(format: "e-style >= .1:\t\"%e\"\n" , 0.1234); |
127 | printf(format: "e-style < .1:\t\"%e\"\n" , 0.001234); |
128 | printf(format: "e-style big:\t\"%.60e\"\n" , 1e20); |
129 | printf (format: "e-style == .1:\t\"%e\"\n" , 0.1); |
130 | printf(format: "f-style == 0:\t\"%f\"\n" , 0.0); |
131 | printf(format: "f-style >= 1:\t\"%f\"\n" , 12.34); |
132 | printf(format: "f-style >= .1:\t\"%f\"\n" , 0.1234); |
133 | printf(format: "f-style < .1:\t\"%f\"\n" , 0.001234); |
134 | printf(format: "g-style == 0:\t\"%g\"\n" , 0.0); |
135 | printf(format: "g-style >= 1:\t\"%g\"\n" , 12.34); |
136 | printf(format: "g-style >= .1:\t\"%g\"\n" , 0.1234); |
137 | printf(format: "g-style < .1:\t\"%g\"\n" , 0.001234); |
138 | printf(format: "g-style big:\t\"%.60g\"\n" , 1e20); |
139 | |
140 | printf(format: "Lf-style == 0:\t\"%Lf\"\n" , (long double) 0.0); |
141 | printf(format: "Lf-style >= 1:\t\"%Lf\"\n" , (long double) 12.34); |
142 | printf(format: "Lf-style >= .1:\t\"%Lf\"\n" , (long double) 0.1234); |
143 | printf(format: "Lf-style < .1:\t\"%Lf\"\n" , (long double) 0.001234); |
144 | printf(format: "Lg-style == 0:\t\"%Lg\"\n" , (long double) 0.0); |
145 | printf(format: "Lg-style >= 1:\t\"%Lg\"\n" , (long double) 12.34); |
146 | printf(format: "Lg-style >= .1:\t\"%Lg\"\n" , (long double) 0.1234); |
147 | printf(format: "Lg-style < .1:\t\"%Lg\"\n" , (long double) 0.001234); |
148 | printf(format: "Lg-style big:\t\"%.60Lg\"\n" , (long double) 1e20); |
149 | |
150 | printf (format: " %6.5f\n" , .099999999860301614); |
151 | printf (format: " %6.5f\n" , .1); |
152 | printf (format: "x%5.4fx\n" , .5); |
153 | |
154 | printf (format: " %6.5Lf\n" , (long double) .099999999860301614); |
155 | printf (format: " %6.5Lf\n" , (long double) .1); |
156 | printf (format: "x%5.4Lfx\n" , (long double) .5); |
157 | |
158 | printf (format: "%#03x\n" , 1); |
159 | |
160 | printf (format: "something really insane: %.10000f\n" , 1.0); |
161 | printf (format: "something really insane (long double): %.10000Lf\n" , |
162 | (long double) 1.0); |
163 | |
164 | { |
165 | double d = FLT_MIN; |
166 | int niter = 17; |
167 | |
168 | while (niter-- != 0) |
169 | printf (format: "%.17e\n" , d / 2); |
170 | fflush (stdout); |
171 | } |
172 | |
173 | printf (format: "%15.5e\n" , 4.9406564584124654e-324); |
174 | |
175 | #define FORMAT "|%12.4f|%12.4e|%12.4g|%12.4Lf|%12.4Lg|\n" |
176 | printf (FORMAT, 0.0, 0.0, 0.0, |
177 | (long double) 0.0, (long double) 0.0); |
178 | printf (FORMAT, 1.0, 1.0, 1.0, |
179 | (long double) 1.0, (long double) 1.0); |
180 | printf (FORMAT, -1.0, -1.0, -1.0, |
181 | (long double) -1.0, (long double) -1.0); |
182 | printf (FORMAT, 100.0, 100.0, 100.0, |
183 | (long double) 100.0, (long double) 100.0); |
184 | printf (FORMAT, 1000.0, 1000.0, 1000.0, |
185 | (long double) 1000.0, (long double) 1000.0); |
186 | printf (FORMAT, 10000.0, 10000.0, 10000.0, |
187 | (long double) 10000.0, (long double) 10000.0); |
188 | printf (FORMAT, 12345.0, 12345.0, 12345.0, |
189 | (long double) 12345.0, (long double) 12345.0); |
190 | printf (FORMAT, 100000.0, 100000.0, 100000.0, |
191 | (long double) 100000.0, (long double) 100000.0); |
192 | printf (FORMAT, 123456.0, 123456.0, 123456.0, |
193 | (long double) 123456.0, (long double) 123456.0); |
194 | #undef FORMAT |
195 | |
196 | { |
197 | char buf[20]; |
198 | char buf2[512]; |
199 | printf (format: "snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n" , |
200 | snprintf (s: buf, maxlen: sizeof (buf), format: "%30s" , "foo" ), (int) sizeof (buf), |
201 | buf); |
202 | printf (format: "snprintf (\"%%.999999u\", 10) == %d\n" , |
203 | snprintf (s: buf2, maxlen: sizeof (buf2), format: "%.999999u" , 10)); |
204 | } |
205 | |
206 | printf(format: "%.8f\n" , DBL_MAX); |
207 | printf(format: "%.8f\n" , -DBL_MAX); |
208 | printf (format: "%e should be 1.234568e+06\n" , 1234567.8); |
209 | printf (format: "%f should be 1234567.800000\n" , 1234567.8); |
210 | printf (format: "%g should be 1.23457e+06\n" , 1234567.8); |
211 | printf (format: "%g should be 123.456\n" , 123.456); |
212 | printf (format: "%g should be 1e+06\n" , 1000000.0); |
213 | printf (format: "%g should be 10\n" , 10.0); |
214 | printf (format: "%g should be 0.02\n" , 0.02); |
215 | |
216 | #if 0 |
217 | /* This test rather checks the way the compiler handles constant |
218 | folding. gcc behavior wrt to this changed in 3.2 so it is not a |
219 | portable test. */ |
220 | { |
221 | double x=1.0; |
222 | printf("%.17f\n" ,(1.0/x/10.0+1.0)*x-x); |
223 | } |
224 | #endif |
225 | |
226 | { |
227 | char buf[200]; |
228 | |
229 | sprintf(buf,"%*s%*s%*s" ,-1,"one" ,-20,"two" ,-30,"three" ); |
230 | |
231 | result |= strcmp (buf, |
232 | "onetwo three " ); |
233 | |
234 | puts (s: result != 0 ? "Test failed!" : "Test ok." ); |
235 | } |
236 | |
237 | { |
238 | char buf[200]; |
239 | |
240 | sprintf (buf, "%07Lo" , 040000000000ll); |
241 | printf (format: "sprintf (buf, \"%%07Lo\", 040000000000ll) = %s" , buf); |
242 | |
243 | if (strcmp (buf, "40000000000" ) != 0) |
244 | { |
245 | result = 1; |
246 | fputs ("\tFAILED" , stdout); |
247 | } |
248 | puts (s: "" ); |
249 | } |
250 | |
251 | printf (format: "printf (\"%%hhu\", %u) = %hhu\n" , UCHAR_MAX + 2, UCHAR_MAX + 2); |
252 | printf (format: "printf (\"%%hu\", %u) = %hu\n" , USHRT_MAX + 2, USHRT_MAX + 2); |
253 | printf (format: "printf (\"%%hhi\", %i) = %hhi\n" , UCHAR_MAX + 2, UCHAR_MAX + 2); |
254 | printf (format: "printf (\"%%hi\", %i) = %hi\n" , USHRT_MAX + 2, USHRT_MAX + 2); |
255 | |
256 | printf (format: "printf (\"%%1$hhu\", %2$u) = %1$hhu\n" , |
257 | UCHAR_MAX + 2, UCHAR_MAX + 2); |
258 | printf (format: "printf (\"%%1$hu\", %2$u) = %1$hu\n" , USHRT_MAX + 2, USHRT_MAX + 2); |
259 | printf (format: "printf (\"%%1$hhi\", %2$i) = %1$hhi\n" , |
260 | UCHAR_MAX + 2, UCHAR_MAX + 2); |
261 | printf (format: "printf (\"%%1$hi\", %2$i) = %1$hi\n" , USHRT_MAX + 2, USHRT_MAX + 2); |
262 | |
263 | puts (s: "--- Should be no further output. ---" ); |
264 | rfg1 (); |
265 | rfg2 (); |
266 | rfg3 (); |
267 | |
268 | { |
269 | char bytes[7]; |
270 | char buf[20]; |
271 | |
272 | memset (bytes, '\xff', sizeof bytes); |
273 | sprintf (buf, "foo%hhn\n" , &bytes[3]); |
274 | if (bytes[0] != '\xff' || bytes[1] != '\xff' || bytes[2] != '\xff' |
275 | || bytes[4] != '\xff' || bytes[5] != '\xff' || bytes[6] != '\xff') |
276 | { |
277 | puts (s: "%hhn overwrite more bytes" ); |
278 | result = 1; |
279 | } |
280 | if (bytes[3] != 3) |
281 | { |
282 | puts (s: "%hhn wrote incorrect value" ); |
283 | result = 1; |
284 | } |
285 | } |
286 | |
287 | return result != 0; |
288 | } |
289 | |
290 | static void |
291 | rfg1 (void) |
292 | { |
293 | char buf[100]; |
294 | |
295 | sprintf (buf, "%5.s" , "xyz" ); |
296 | if (strcmp (buf, " " ) != 0) |
297 | printf (format: "got: '%s', expected: '%s'\n" , buf, " " ); |
298 | sprintf (buf, "%5.f" , 33.3); |
299 | if (strcmp (buf, " 33" ) != 0) |
300 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 33" ); |
301 | sprintf (buf, "%5.Lf" , (long double) 33.3); |
302 | if (strcmp (buf, " 33" ) != 0) |
303 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 33" ); |
304 | sprintf (buf, "%8.e" , 33.3e7); |
305 | if (strcmp (buf, " 3e+08" ) != 0) |
306 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 3e+08" ); |
307 | sprintf (buf, "%8.E" , 33.3e7); |
308 | if (strcmp (buf, " 3E+08" ) != 0) |
309 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 3E+08" ); |
310 | sprintf (buf, "%.g" , 33.3); |
311 | if (strcmp (buf, "3e+01" ) != 0) |
312 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3e+01" ); |
313 | sprintf (buf, "%.Lg" , (long double) 33.3); |
314 | if (strcmp (buf, "3e+01" ) != 0) |
315 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3e+01" ); |
316 | sprintf (buf, "%.G" , 33.3); |
317 | if (strcmp (buf, "3E+01" ) != 0) |
318 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3E+01" ); |
319 | } |
320 | |
321 | static void |
322 | rfg2 (void) |
323 | { |
324 | int prec; |
325 | char buf[100]; |
326 | |
327 | prec = 0; |
328 | sprintf (buf, "%.*g" , prec, 3.3); |
329 | if (strcmp (buf, "3" ) != 0) |
330 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3" ); |
331 | prec = 0; |
332 | sprintf (buf, "%.*G" , prec, 3.3); |
333 | if (strcmp (buf, "3" ) != 0) |
334 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3" ); |
335 | prec = 0; |
336 | sprintf (buf, "%7.*G" , prec, 3.33); |
337 | if (strcmp (buf, " 3" ) != 0) |
338 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 3" ); |
339 | prec = 0; |
340 | sprintf (buf, "%.*Lg" , prec, (long double) 3.3); |
341 | if (strcmp (buf, "3" ) != 0) |
342 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3" ); |
343 | prec = 0; |
344 | sprintf (buf, "%.*LG" , prec, (long double) 3.3); |
345 | if (strcmp (buf, "3" ) != 0) |
346 | printf (format: "got: '%s', expected: '%s'\n" , buf, "3" ); |
347 | prec = 0; |
348 | sprintf (buf, "%7.*LG" , prec, (long double) 3.33); |
349 | if (strcmp (buf, " 3" ) != 0) |
350 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 3" ); |
351 | prec = 3; |
352 | sprintf (buf, "%04.*o" , prec, 33); |
353 | if (strcmp (buf, " 041" ) != 0) |
354 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 041" ); |
355 | prec = 7; |
356 | sprintf (buf, "%09.*u" , prec, 33); |
357 | if (strcmp (buf, " 0000033" ) != 0) |
358 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 0000033" ); |
359 | prec = 3; |
360 | sprintf (buf, "%04.*x" , prec, 33); |
361 | if (strcmp (buf, " 021" ) != 0) |
362 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 021" ); |
363 | prec = 3; |
364 | sprintf (buf, "%04.*X" , prec, 33); |
365 | if (strcmp (buf, " 021" ) != 0) |
366 | printf (format: "got: '%s', expected: '%s'\n" , buf, " 021" ); |
367 | } |
368 | |
369 | static void |
370 | rfg3 (void) |
371 | { |
372 | char buf[100]; |
373 | double g = 5.0000001; |
374 | unsigned long l = 1234567890; |
375 | double d = 321.7654321; |
376 | const char s[] = "test-string" ; |
377 | int i = 12345; |
378 | int h = 1234; |
379 | |
380 | sprintf (buf, |
381 | "%1$*5$d %2$*6$hi %3$*7$lo %4$*8$f %9$*12$e %10$*13$g %11$*14$s" , |
382 | i, h, l, d, 8, 5, 14, 14, d, g, s, 14, 3, 14); |
383 | if (strcmp (buf, |
384 | " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string" ) != 0) |
385 | printf (format: "got: '%s', expected: '%s'\n" , buf, |
386 | " 12345 1234 11145401322 321.765432 3.217654e+02 5 test-string" ); |
387 | } |
388 | |
389 | #define TEST_FUNCTION do_test () |
390 | #include "../test-skeleton.c" |
391 | |