1 /* $NetBSD: t_printf.c,v 1.18 2024/05/11 14:39:53 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/resource.h>
31 
32 #include <atf-c.h>
33 #include <errno.h>
34 #include <float.h>
35 #include <math.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 
42 ATF_TC(snprintf_c99);
ATF_TC_HEAD(snprintf_c99,tc)43 ATF_TC_HEAD(snprintf_c99, tc)
44 {
45 
46           atf_tc_set_md_var(tc, "descr",
47               "Test printf(3) C99 conformance (PR lib/22019)");
48 }
49 
ATF_TC_BODY(snprintf_c99,tc)50 ATF_TC_BODY(snprintf_c99, tc)
51 {
52           char s[4];
53 
54           (void)memset(s, '\0', sizeof(s));
55           (void)snprintf(s, sizeof(s), "%#.o", 0);
56           (void)printf("printf = %#.o\n", 0);
57           (void)fprintf(stderr, "snprintf = %s", s);
58 
59           ATF_REQUIRE(strlen(s) == 1);
60           ATF_REQUIRE(s[0] == '0');
61 }
62 
63 ATF_TC(snprintf_dotzero);
ATF_TC_HEAD(snprintf_dotzero,tc)64 ATF_TC_HEAD(snprintf_dotzero, tc)
65 {
66 
67           atf_tc_set_md_var(tc, "descr",
68               "PR lib/32951: %%.0f formats (0.0,0.5] to \"0.\"");
69 }
70 
ATF_TC_BODY(snprintf_dotzero,tc)71 ATF_TC_BODY(snprintf_dotzero, tc)
72 {
73           char s[4];
74 
75           ATF_CHECK(snprintf(s, sizeof(s), "%.0f", 0.1) == 1);
76           ATF_REQUIRE_STREQ(s, "0");
77 }
78 
79 ATF_TC(snprintf_posarg);
ATF_TC_HEAD(snprintf_posarg,tc)80 ATF_TC_HEAD(snprintf_posarg, tc)
81 {
82 
83           atf_tc_set_md_var(tc, "descr", "test for positional arguments");
84 }
85 
ATF_TC_BODY(snprintf_posarg,tc)86 ATF_TC_BODY(snprintf_posarg, tc)
87 {
88           char s[16];
89 
90           ATF_CHECK(snprintf(s, sizeof(s), "%1$d", -23) == 3);
91           ATF_REQUIRE_STREQ(s, "-23");
92 }
93 
94 ATF_TC(snprintf_posarg_width);
ATF_TC_HEAD(snprintf_posarg_width,tc)95 ATF_TC_HEAD(snprintf_posarg_width, tc)
96 {
97 
98           atf_tc_set_md_var(tc, "descr", "test for positional arguments with "
99               "field width");
100 }
101 
ATF_TC_BODY(snprintf_posarg_width,tc)102 ATF_TC_BODY(snprintf_posarg_width, tc)
103 {
104           char s[16];
105 
106           ATF_CHECK(snprintf(s, sizeof(s), "%1$*2$d", -23, 4) == 4);
107           ATF_REQUIRE_STREQ(s, " -23");
108 }
109 
110 ATF_TC(snprintf_posarg_error);
ATF_TC_HEAD(snprintf_posarg_error,tc)111 ATF_TC_HEAD(snprintf_posarg_error, tc)
112 {
113 
114           atf_tc_set_md_var(tc, "descr", "test for positional arguments out "
115               "of bounds");
116 }
117 
ATF_TC_BODY(snprintf_posarg_error,tc)118 ATF_TC_BODY(snprintf_posarg_error, tc)
119 {
120           char s[16], fmt[32];
121 
122           snprintf(fmt, sizeof(fmt), "%%%zu$d", SIZE_MAX / sizeof(size_t));
123 
124           ATF_CHECK(snprintf(s, sizeof(s), fmt, -23) == -1);
125 }
126 
127 ATF_TC(snprintf_float);
ATF_TC_HEAD(snprintf_float,tc)128 ATF_TC_HEAD(snprintf_float, tc)
129 {
130 
131           atf_tc_set_md_var(tc, "descr", "test that floating conversions don't"
132               " leak memory");
133 }
134 
ATF_TC_BODY(snprintf_float,tc)135 ATF_TC_BODY(snprintf_float, tc)
136 {
137           union {
138                     double d;
139                     uint64_t bits;
140           } u;
141           uint32_t ul, uh;
142           time_t now;
143           char buf[1000];
144           struct rlimit rl;
145 
146           rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
147           ATF_CHECK(setrlimit(RLIMIT_AS, &rl) != -1);
148           rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
149           ATF_CHECK(setrlimit(RLIMIT_DATA, &rl) != -1);
150 
151           time(&now);
152           srand(now);
153           for (size_t i = 0; i < 10000; i++) {
154                     ul = rand();
155                     uh = rand();
156                     u.bits = (uint64_t)uh << 32 | ul;
157                     ATF_CHECK(snprintf(buf, sizeof buf, " %.2f", u.d) != -1);
158           }
159 }
160 
161 ATF_TC(sprintf_zeropad);
ATF_TC_HEAD(sprintf_zeropad,tc)162 ATF_TC_HEAD(sprintf_zeropad, tc)
163 {
164           atf_tc_set_md_var(tc, "descr",
165               "Test output format zero padding (PR lib/44113)");
166 }
167 
ATF_TC_BODY(sprintf_zeropad,tc)168 ATF_TC_BODY(sprintf_zeropad, tc)
169 {
170           char str[1024];
171 
172           ATF_CHECK(sprintf(str, "%010f", 0.0) == 10);
173           ATF_REQUIRE_STREQ(str, "000.000000");
174 
175           /* ieeefp */
176 #ifndef __vax__
177           /* printf(3) should ignore zero padding for nan/inf */
178           ATF_CHECK(sprintf(str, "%010f", NAN) == 10);
179           ATF_REQUIRE_STREQ(str, "       nan");
180           ATF_CHECK(sprintf(str, "%010f", INFINITY) == 10);
181           ATF_REQUIRE_STREQ(str, "       inf");
182 #endif
183 }
184 
185 ATF_TC(snprintf_double_a);
ATF_TC_HEAD(snprintf_double_a,tc)186 ATF_TC_HEAD(snprintf_double_a, tc)
187 {
188           atf_tc_set_md_var(tc, "descr", "Test printf a format");
189 }
190 
ATF_TC_BODY(snprintf_double_a,tc)191 ATF_TC_BODY(snprintf_double_a, tc)
192 {
193           char buf[1000];
194 
195           snprintf(buf, sizeof buf, "%.3a", (double)10.6);
196           ATF_CHECK_MSG((strcmp(buf, "0x1.533p+3") == 0 ||
197                     strcmp(buf, "0x2.a66p+2") == 0 ||
198                     strcmp(buf, "0x5.4cdp+1") == 0 ||
199                     strcmp(buf, "0xa.99ap+0") == 0),
200               "buf=%s", buf);
201 
202           snprintf(buf, sizeof buf, "%a", (double)0.125);
203           ATF_CHECK_MSG((strcmp(buf, "0x1p-3") == 0 ||
204                     strcmp(buf, "0x2p-4") == 0 ||
205                     strcmp(buf, "0x4p-5") == 0 ||
206                     strcmp(buf, "0x8p-6") == 0),
207               "buf=%s", buf);
208 }
209 
210 ATF_TC(snprintf_long_double_a);
ATF_TC_HEAD(snprintf_long_double_a,tc)211 ATF_TC_HEAD(snprintf_long_double_a, tc)
212 {
213           atf_tc_set_md_var(tc, "descr", "Test printf La format");
214 }
215 
ATF_TC_BODY(snprintf_long_double_a,tc)216 ATF_TC_BODY(snprintf_long_double_a, tc)
217 {
218           char buf[1000];
219 
220           snprintf(buf, sizeof buf, "%.3La", 10.6L);
221           ATF_CHECK_MSG((strcmp(buf, "0x1.533p+3") == 0 ||
222                     strcmp(buf, "0x2.a66p+2") == 0 ||
223                     strcmp(buf, "0x5.4cdp+1") == 0 ||
224                     strcmp(buf, "0xa.99ap+0") == 0),
225               "buf=%s", buf);
226 
227           snprintf(buf, sizeof buf, "%La", 0.125L);
228           ATF_CHECK_MSG((strcmp(buf, "0x1p-3") == 0 ||
229                     strcmp(buf, "0x2p-4") == 0 ||
230                     strcmp(buf, "0x4p-5") == 0 ||
231                     strcmp(buf, "0x8p-6") == 0),
232               "buf=%s", buf);
233 
234           /*
235            * Test case adapted from:
236            *
237            * https://mail-index.netbsd.org/tech-userlevel/2020/04/11/msg012329.html
238            */
239 #if LDBL_MAX_EXP >= 16384 && LDBL_MANT_DIG >= 64
240           snprintf(buf, sizeof buf, "%La", -0xc.ecececececececep+3788L);
241           ATF_CHECK_MSG((strcmp(buf, "-0x1.9d9d9d9d9d9d9d9cp+3791") == 0 ||
242                     strcmp(buf, "-0x3.3b3b3b3b3b3b3b38p+3790") == 0 ||
243                     strcmp(buf, "-0x6.7676767676767674p+3789") == 0 ||
244                     strcmp(buf, "-0xc.ecececececececep+3788") == 0),
245               "buf=%s", buf);
246 #endif
247 
248 #if LDBL_MAX_EXP >= 16384 && LDBL_MANT_DIG >= 113
249           snprintf(buf, sizeof buf, "%La",
250               -0x1.cecececececececececececececep+3791L);
251           ATF_CHECK_MSG((strcmp(buf,
252                         "-0x1.cecececececececececececececep+3791") == 0 ||
253                     strcmp(buf, "-0x3.3333333333333338p+3790") == 0 ||
254                     strcmp(buf, "-0x6.767676767676767p+3789") == 0 ||
255                     strcmp(buf, "-0xc.ecececececececep+3788") == 0),
256               "buf=%s", buf);
257 #endif
258 }
259 
260 /* is "long double" and "double" different? */
261 #if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
262     (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
263 #define WIDE_DOUBLE
264 #endif
265 
266 #ifndef WIDE_DOUBLE
267 ATF_TC(pr57250_fix);
ATF_TC_HEAD(pr57250_fix,tc)268 ATF_TC_HEAD(pr57250_fix, tc)
269 {
270           atf_tc_set_md_var(tc, "descr", "Test for PR57250");
271 }
272 
ATF_TC_BODY(pr57250_fix,tc)273 ATF_TC_BODY(pr57250_fix, tc)
274 {
275           char *eptr;
276           char buf[1000];
277           long double ld;
278 
279           errno = 0;
280           ld = strtold("1e309", &eptr);
281           ATF_CHECK(errno != 0);
282           ld = (double)ld;
283           ATF_CHECK(isfinite(ld) == 0);
284           snprintf(buf, sizeof buf, "%Lf\n", ld);
285           ATF_REQUIRE_STREQ(buf, "inf\n");
286 }
287 #endif
288 
289 
ATF_TP_ADD_TCS(tp)290 ATF_TP_ADD_TCS(tp)
291 {
292 
293           ATF_TP_ADD_TC(tp, snprintf_c99);
294           ATF_TP_ADD_TC(tp, snprintf_dotzero);
295           ATF_TP_ADD_TC(tp, snprintf_posarg);
296           ATF_TP_ADD_TC(tp, snprintf_posarg_width);
297           ATF_TP_ADD_TC(tp, snprintf_posarg_error);
298           ATF_TP_ADD_TC(tp, snprintf_float);
299           ATF_TP_ADD_TC(tp, sprintf_zeropad);
300           ATF_TP_ADD_TC(tp, snprintf_double_a);
301           ATF_TP_ADD_TC(tp, snprintf_long_double_a);
302 #ifndef WIDE_DOUBLE
303           ATF_TP_ADD_TC(tp, pr57250_fix);
304 #endif
305 
306           return atf_no_error();
307 }
308