xref: /openbsd/regress/lib/libc/printf/int.c (revision c39afc64)
1 /* $OpenBSD: int.c,v 1.2 2020/07/14 16:40:04 kettenis Exp $ */
2 /*
3  * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Test the %c, %lc, %s, and %ls conversion specifiers with all their
18  * modifiers, in particular with the minus flag, width, and maxbytes.
19  * Also verify that other flags do nothing useful.
20  */
21 #include <err.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 enum	int_size {
29 	S_CHAR,
30 	S_SHORT,
31 	S_INT,
32 	S_LONG,
33 	S_LL,
34 	S_MAX,
35 	S_PTR,
36 	S_SIZE
37 };
38 
39 void	 ti(const char *, enum int_size, long long, const char *);
40 void	 tu(const char *, enum int_size, unsigned long long, const char *);
41 
42 static int	 badret, badlen, badout;	/* Error counters. */
43 static int	 verbose;			/* For debugging. */
44 
45 
46 /*
47  * Print the signed integer i with the format fmt,
48  * check that the result matches what we want,
49  * and report and count the error on failure.
50  */
51 void
ti(const char * fmt,enum int_size sz,long long i,const char * want)52 ti(const char *fmt, enum int_size sz, long long i, const char *want)
53 {
54 	char		 buf[32];
55 	size_t		 len;
56 	int		 irc, happy;
57 
58 	happy = 1;
59 	switch (sz) {
60 	case S_CHAR:
61 		irc = snprintf(buf, sizeof(buf), fmt, (signed char)i);
62 		break;
63 	case S_SHORT:
64 		irc = snprintf(buf, sizeof(buf), fmt, (short)i);
65 		break;
66 	case S_INT:
67 		irc = snprintf(buf, sizeof(buf), fmt, (int)i);
68 		break;
69 	case S_LONG:
70 		irc = snprintf(buf, sizeof(buf), fmt, (long)i);
71 		break;
72 	case S_LL:
73 		irc = snprintf(buf, sizeof(buf), fmt, (long long)i);
74 		break;
75 	case S_MAX:
76 		irc = snprintf(buf, sizeof(buf), fmt, (intmax_t)i);
77 		break;
78 	case S_PTR:
79 		irc = snprintf(buf, sizeof(buf), fmt, (ptrdiff_t)i);
80 		break;
81 	case S_SIZE:
82 		irc = snprintf(buf, sizeof(buf), fmt, (ssize_t)i);
83 		break;
84 	default:
85 		warnx("printf(\"%s\", %lld) unknown size code %d",
86 		    fmt, i, sz);
87 		badret++;
88 		return;
89 	}
90 	len = strlen(want);
91 	if (irc < 0) {
92 		warn("printf(\"%s\", %lld) returned %d", fmt, i, irc);
93 		badret++;
94 		return;
95 	}
96 	if ((unsigned long long)irc != len) {
97 		warnx("printf(\"%s\", %lld) returned %d (expected %zu)",
98 		    fmt, i, irc, len);
99 		badlen++;
100 		happy = 0;
101 	}
102 	if (strcmp(buf, want) != 0) {
103 		warnx("printf(\"%s\", %lld) wrote \"%s\" (expected \"%s\")",
104 		    fmt, i, buf, want);
105 		badout++;
106 		happy = 0;
107 	}
108 	if (verbose && happy)
109 		warnx("printf(\"%s\", %lld) wrote \"%s\" length %d (OK)",
110 		    fmt, i, buf, irc);
111 }
112 
113 /*
114  * Print the unsigned integer i with the format fmt,
115  * check that the result matches what we want,
116  * and report and count the error on failure.
117  */
118 void
tu(const char * fmt,enum int_size sz,unsigned long long i,const char * want)119 tu(const char *fmt, enum int_size sz, unsigned long long i, const char *want)
120 {
121 	char		 buf[32];
122 	size_t		 len;
123 	int		 irc, happy;
124 
125 	happy = 1;
126 	switch (sz) {
127 	case S_CHAR:
128 		irc = snprintf(buf, sizeof(buf), fmt, (unsigned char)i);
129 		break;
130 	case S_SHORT:
131 		irc = snprintf(buf, sizeof(buf), fmt, (unsigned short)i);
132 		break;
133 	case S_INT:
134 		irc = snprintf(buf, sizeof(buf), fmt, (unsigned int)i);
135 		break;
136 	case S_LONG:
137 		irc = snprintf(buf, sizeof(buf), fmt, (unsigned long)i);
138 		break;
139 	case S_LL:
140 		irc = snprintf(buf, sizeof(buf), fmt, (unsigned long long)i);
141 		break;
142 	case S_MAX:
143 		irc = snprintf(buf, sizeof(buf), fmt, (uintmax_t)i);
144 		break;
145 	case S_SIZE:
146 		irc = snprintf(buf, sizeof(buf), fmt, (size_t)i);
147 		break;
148 	default:
149 		warnx("printf(\"%s\", %llu) unknown size code %d",
150 		    fmt, i, sz);
151 		badret++;
152 		return;
153 	}
154 	len = strlen(want);
155 	if (irc < 0) {
156 		warn("printf(\"%s\", %llu) returned %d", fmt, i, irc);
157 		badret++;
158 		return;
159 	}
160 	if ((unsigned long long)irc != len) {
161 		warnx("printf(\"%s\", %llu) returned %d (expected %zu)",
162 		    fmt, i, irc, len);
163 		badlen++;
164 		happy = 0;
165 	}
166 	if (strcmp(buf, want) != 0) {
167 		warnx("printf(\"%s\", %llu) wrote \"%s\" (expected \"%s\")",
168 		    fmt, i, buf, want);
169 		badout++;
170 		happy = 0;
171 	}
172 	if (verbose && happy)
173 		warnx("printf(\"%s\", %llu) wrote \"%s\" length %d (OK)",
174 		    fmt, i, buf, irc);
175 }
176 
177 int
main(int argc,char * argv[])178 main(int argc, char *argv[])
179 {
180 	int		 badarg, picky;
181 	int		 ch;
182 
183 	badarg = picky = 0;
184 	while ((ch = getopt(argc, argv, "pv")) != -1) {
185 		switch (ch) {
186 		case 'p':
187 			picky = 1;
188 			break;
189 		case 'v':
190 			verbose = 1;
191 			break;
192 		default:
193 			badarg = 1;
194 			break;
195 		}
196 	}
197 	argc -= optind;
198 	argv += optind;
199 	if (argc > 0) {
200 		warnx("unexpected argument \"%s\"", *argv);
201 		badarg = 1;
202 	}
203 	if (badarg) {
204 		fputs("usage: int [-pv]\n", stderr);
205 		return 1;
206 	}
207 
208 	/*
209 	 * Valid use cases of %d.
210 	 */
211 
212 	ti("<%d>", S_INT, 0, "<0>");
213 	ti("<%d>", S_INT, 1, "<1>");
214 	ti("<%d>", S_INT, -1, "<-1>");
215 	ti("<%d>", S_INT, 42, "<42>");
216 	ti("<%d>", S_INT, INT32_MAX, "<2147483647>");
217 	ti("<%d>", S_INT, INT32_MIN, "<-2147483648>");
218 	ti("<% d>", S_INT, 42, "< 42>");
219 	ti("<% d>", S_INT, -42, "<-42>");
220 	ti("<%+d>", S_INT, 42, "<+42>");
221 	ti("<%+d>", S_INT, -42, "<-42>");
222 	ti("<% +d>", S_INT, 42, "<+42>");
223 	ti("<% +d>", S_INT, -42, "<-42>");
224 	ti("<%-4d>", S_INT, 42, "<42  >");
225 	ti("<% -4d>", S_INT, 42, "< 42 >");
226 	ti("<%+-4d>", S_INT, 42, "<+42 >");
227 	ti("<%04d>", S_INT, 42, "<0042>");
228 	ti("<%-04d>", S_INT, 42, "<42  >");
229 	ti("<% 04d>", S_INT, 42, "< 042>");
230 	ti("<%+04d>", S_INT, 42, "<+042>");
231 	ti("<%4.3d>", S_INT, 42, "< 042>");
232 	ti("<% 5.3d>", S_INT, 42, "<  042>");
233 	ti("<%+5.3d>", S_INT, 42, "< +042>");
234 	ti("<%-4.3d>", S_INT, 42, "<042 >");
235 	ti("<%04.3d>", S_INT, 42, "< 042>");
236 
237 	ti("<%hhd>", S_CHAR, INT8_MIN, "<-128>");
238 	ti("<%hhd>", S_CHAR, -1, "<-1>");
239 	ti("<%hhd>", S_CHAR, 0, "<0>");
240 	ti("<%hhd>", S_CHAR, 1, "<1>");
241 	ti("<%hhd>", S_CHAR, INT8_MAX, "<127>");
242 	ti("<%+.4hhd>", S_CHAR, 42, "<+0042>");
243 	ti("<% 04hhd>", S_CHAR, 42, "< 042>");
244 
245 	ti("<%hd>", S_SHORT, INT16_MIN, "<-32768>");
246 	ti("<%hd>", S_SHORT, -1, "<-1>");
247 	ti("<%hd>", S_SHORT, 0, "<0>");
248 	ti("<%hd>", S_SHORT, 1, "<1>");
249 	ti("<%hd>", S_SHORT, INT16_MAX, "<32767>");
250 
251 	ti("<%hld>", S_LONG, INT32_MIN, "<-2147483648>");
252 	ti("<%hld>", S_LONG, -1, "<-1>");
253 	ti("<%hld>", S_LONG, 0, "<0>");
254 	ti("<%hld>", S_LONG, 1, "<1>");
255 	ti("<%hld>", S_LONG, INT32_MAX, "<2147483647>");
256 
257 	ti("<%hlld>", S_LL, INT64_MIN, "<-9223372036854775808>");
258 	ti("<%hlld>", S_LL, -1, "<-1>");
259 	ti("<%hlld>", S_LL, 0, "<0>");
260 	ti("<%hlld>", S_LL, 1, "<1>");
261 	ti("<%hlld>", S_LL, INT64_MAX, "<9223372036854775807>");
262 	ti("<%h-19lld>", S_LL, 123456789123456789LL, "<123456789123456789 >");
263 
264 	ti("<%hjd>", S_MAX, INT64_MIN, "<-9223372036854775808>");
265 	ti("<%hjd>", S_MAX, -1, "<-1>");
266 	ti("<%hjd>", S_MAX, 0, "<0>");
267 	ti("<%hjd>", S_MAX, 1, "<1>");
268 	ti("<%hjd>", S_MAX, INT64_MAX, "<9223372036854775807>");
269 
270 	ti("<%htd>", S_PTR, INT32_MIN, "<-2147483648>");
271 	ti("<%htd>", S_PTR, -1, "<-1>");
272 	ti("<%htd>", S_PTR, 0, "<0>");
273 	ti("<%htd>", S_PTR, 1, "<1>");
274 	ti("<%htd>", S_PTR, INT32_MAX, "<2147483647>");
275 
276 	ti("<%hzd>", S_SIZE, INT32_MIN, "<-2147483648>");
277 	ti("<%hzd>", S_SIZE, -1, "<-1>");
278 	ti("<%hzd>", S_SIZE, 0, "<0>");
279 	ti("<%hzd>", S_SIZE, 1, "<1>");
280 	ti("<%hzd>", S_SIZE, INT32_MAX, "<2147483647>");
281 
282 	/*
283 	 * Undefined behaviour of %d.
284 	 * Do not test by default to avoid noise.
285 	 * But provide the tests anyway to help track down
286 	 * unintended changes of behaviour when needed.
287 	 */
288 
289 	if (picky) {
290 		ti("<%#d>", S_INT, 42, "<42>");
291 		ti("<%Ld>", S_INT, 42, "<42>");
292 	}
293 
294 	/*
295 	 * Valid use cases of %u.
296 	 */
297 
298 	tu("<%u>", S_INT, 0, "<0>");
299 	tu("<%u>", S_INT, 1, "<1>");
300 	tu("<%u>", S_INT, 42, "<42>");
301 	tu("<%u>", S_INT, UINT32_MAX, "<4294967295>");
302 	tu("<%-4u>", S_INT, 42, "<42  >");
303 	tu("<%04u>", S_INT, 42, "<0042>");
304 	tu("<%-04u>", S_INT, 42, "<42  >");
305 	tu("<%4.3u>", S_INT, 42, "< 042>");
306 	tu("<%-4.3u>", S_INT, 42, "<042 >");
307 	tu("<%04.3u>", S_INT, 42, "< 042>");
308 
309 	tu("<%hhu>", S_CHAR, 0, "<0>");
310 	tu("<%hhu>", S_CHAR, UINT8_MAX, "<255>");
311 	tu("<%hhu>", S_CHAR, -1, "<255>");
312 	tu("<%-4hhu>", S_CHAR, 42, "<42  >");
313 	tu("<%04hhu>", S_CHAR, 42, "<0042>");
314 
315 	tu("<%hu>", S_SHORT, 0, "<0>");
316 	tu("<%hu>", S_SHORT, UINT16_MAX, "<65535>");
317 	tu("<%hlu>", S_LONG, 0, "<0>");
318 	tu("<%hlu>", S_LONG, UINT32_MAX, "<4294967295>");
319 	tu("<%hllu>", S_LL, 0, "<0>");
320 	tu("<%hllu>", S_LL, UINT64_MAX, "<18446744073709551615>");
321 	tu("<%h-19llu>", S_LL, 123456789123456789ULL, "<123456789123456789 >");
322 	tu("<%hju>", S_MAX, 0, "<0>");
323 	tu("<%hju>", S_MAX, UINT64_MAX, "<18446744073709551615>");
324 	tu("<%hzu>", S_SIZE, 0, "<0>");
325 	tu("<%hzu>", S_SIZE, UINT32_MAX, "<4294967295>");
326 
327 	tu("<%hho>", S_CHAR, 0, "<0>");
328 	tu("<%#hho>", S_CHAR, 0, "<0>");
329 	tu("<%hho>", S_CHAR, UINT8_MAX, "<377>");
330 	tu("<%#hho>", S_CHAR, UINT8_MAX, "<0377>");
331 	tu("<%hho>", S_CHAR, -1, "<377>");
332 	tu("<%#hho>", S_CHAR, -1, "<0377>");
333 	tu("<%-4hho>", S_CHAR, 42, "<52  >");
334 	tu("<%#-4hho>", S_CHAR, 42, "<052 >");
335 	tu("<%04hho>", S_CHAR, 42, "<0052>");
336 	tu("<%#04hho>", S_CHAR, 42, "<0052>");
337 
338 	tu("<%hx>", S_SHORT, 0, "<0>");
339 	tu("<%#hx>", S_SHORT, 0, "<0>");
340 	tu("<%hX>", S_SHORT, 0, "<0>");
341 	tu("<%#hX>", S_SHORT, 0, "<0>");
342 	tu("<%hx>", S_SHORT, 1, "<1>");
343 	tu("<%#hx>", S_SHORT, 1, "<0x1>");
344 	tu("<%hX>", S_SHORT, 1, "<1>");
345 	tu("<%#hX>", S_SHORT, 1, "<0X1>");
346 	tu("<%hx>", S_SHORT, 10, "<a>");
347 	tu("<%#hx>", S_SHORT, 10, "<0xa>");
348 	tu("<%hX>", S_SHORT, 10, "<A>");
349 	tu("<%#hX>", S_SHORT, 10, "<0XA>");
350 	tu("<%hx>", S_SHORT, UINT16_MAX, "<ffff>");
351 	tu("<%#hx>", S_SHORT, UINT16_MAX, "<0xffff>");
352 	tu("<%hX>", S_SHORT, UINT16_MAX, "<FFFF>");
353 	tu("<%#hX>", S_SHORT, UINT16_MAX, "<0XFFFF>");
354 
355 	/*
356 	 * Undefined behaviour of %u.
357 	 */
358 
359 	if (picky) {
360 		tu("<%#u>", S_INT, 42, "<42>");
361 		tu("<% u>", S_INT, 42, "<42>");
362 		tu("<%+u>", S_INT, 42, "<42>");
363 		tu("<%Lu>", S_INT, 42, "<42>");
364 	}
365 
366 	/*
367 	 * Summarize the results.
368 	 */
369 
370 	if (badret + badlen + badout)
371 		errx(1, "ERRORS: %d fail + %d mismatch (incl. %d bad length)",
372 		    badret, badout, badlen);
373 	else if (verbose)
374 		warnx("SUCCESS");
375 	return 0;
376 }
377