1*c5c7b2d6Sriastradh /* $NetBSD: t_printf.c,v 1.18 2024/05/11 14:39:53 riastradh Exp $ */
2aa3f9890Sjruoho
3aa3f9890Sjruoho /*-
4aa3f9890Sjruoho * Copyright (c) 2010 The NetBSD Foundation, Inc.
5aa3f9890Sjruoho * All rights reserved.
6aa3f9890Sjruoho *
7aa3f9890Sjruoho * Redistribution and use in source and binary forms, with or without
8aa3f9890Sjruoho * modification, are permitted provided that the following conditions
9aa3f9890Sjruoho * are met:
10aa3f9890Sjruoho * 1. Redistributions of source code must retain the above copyright
11aa3f9890Sjruoho * notice, this list of conditions and the following disclaimer.
12aa3f9890Sjruoho * 2. Redistributions in binary form must reproduce the above copyright
13aa3f9890Sjruoho * notice, this list of conditions and the following disclaimer in the
14aa3f9890Sjruoho * documentation and/or other materials provided with the distribution.
15aa3f9890Sjruoho *
16aa3f9890Sjruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17aa3f9890Sjruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18aa3f9890Sjruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19aa3f9890Sjruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20aa3f9890Sjruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21aa3f9890Sjruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22aa3f9890Sjruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23aa3f9890Sjruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24aa3f9890Sjruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25aa3f9890Sjruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26aa3f9890Sjruoho * POSSIBILITY OF SUCH DAMAGE.
27aa3f9890Sjruoho */
28aa3f9890Sjruoho
290eef4e1eSchristos #include <sys/types.h>
300eef4e1eSchristos #include <sys/resource.h>
315c6dfe98Sriastradh
32aa3f9890Sjruoho #include <atf-c.h>
335c6dfe98Sriastradh #include <errno.h>
345c6dfe98Sriastradh #include <float.h>
35aa3f9890Sjruoho #include <math.h>
363fa39ef9Schristos #include <stdint.h>
375c6dfe98Sriastradh #include <stdio.h>
385c6dfe98Sriastradh #include <stdlib.h>
39aa3f9890Sjruoho #include <string.h>
400eef4e1eSchristos #include <time.h>
41aa3f9890Sjruoho
42a6bc77fdSjruoho ATF_TC(snprintf_c99);
ATF_TC_HEAD(snprintf_c99,tc)43a6bc77fdSjruoho ATF_TC_HEAD(snprintf_c99, tc)
44a6bc77fdSjruoho {
45a6bc77fdSjruoho
46a6bc77fdSjruoho atf_tc_set_md_var(tc, "descr",
47a6bc77fdSjruoho "Test printf(3) C99 conformance (PR lib/22019)");
48a6bc77fdSjruoho }
49a6bc77fdSjruoho
ATF_TC_BODY(snprintf_c99,tc)50a6bc77fdSjruoho ATF_TC_BODY(snprintf_c99, tc)
51a6bc77fdSjruoho {
52a6bc77fdSjruoho char s[4];
53a6bc77fdSjruoho
54a6bc77fdSjruoho (void)memset(s, '\0', sizeof(s));
55a6bc77fdSjruoho (void)snprintf(s, sizeof(s), "%#.o", 0);
56a6bc77fdSjruoho (void)printf("printf = %#.o\n", 0);
57a6bc77fdSjruoho (void)fprintf(stderr, "snprintf = %s", s);
58a6bc77fdSjruoho
59a6bc77fdSjruoho ATF_REQUIRE(strlen(s) == 1);
60a6bc77fdSjruoho ATF_REQUIRE(s[0] == '0');
61a6bc77fdSjruoho }
62a6bc77fdSjruoho
63d808fe5fSjruoho ATF_TC(snprintf_dotzero);
ATF_TC_HEAD(snprintf_dotzero,tc)64d808fe5fSjruoho ATF_TC_HEAD(snprintf_dotzero, tc)
65aa3f9890Sjruoho {
66aa3f9890Sjruoho
67a6bc77fdSjruoho atf_tc_set_md_var(tc, "descr",
68a42982feSjoerg "PR lib/32951: %%.0f formats (0.0,0.5] to \"0.\"");
69aa3f9890Sjruoho }
70aa3f9890Sjruoho
ATF_TC_BODY(snprintf_dotzero,tc)71d808fe5fSjruoho ATF_TC_BODY(snprintf_dotzero, tc)
72aa3f9890Sjruoho {
73aa3f9890Sjruoho char s[4];
74aa3f9890Sjruoho
75aa3f9890Sjruoho ATF_CHECK(snprintf(s, sizeof(s), "%.0f", 0.1) == 1);
76aa3f9890Sjruoho ATF_REQUIRE_STREQ(s, "0");
77aa3f9890Sjruoho }
78aa3f9890Sjruoho
793fa39ef9Schristos ATF_TC(snprintf_posarg);
ATF_TC_HEAD(snprintf_posarg,tc)803fa39ef9Schristos ATF_TC_HEAD(snprintf_posarg, tc)
813fa39ef9Schristos {
823fa39ef9Schristos
833fa39ef9Schristos atf_tc_set_md_var(tc, "descr", "test for positional arguments");
843fa39ef9Schristos }
853fa39ef9Schristos
ATF_TC_BODY(snprintf_posarg,tc)863fa39ef9Schristos ATF_TC_BODY(snprintf_posarg, tc)
873fa39ef9Schristos {
883fa39ef9Schristos char s[16];
893fa39ef9Schristos
903fa39ef9Schristos ATF_CHECK(snprintf(s, sizeof(s), "%1$d", -23) == 3);
913fa39ef9Schristos ATF_REQUIRE_STREQ(s, "-23");
923fa39ef9Schristos }
933fa39ef9Schristos
943fa39ef9Schristos ATF_TC(snprintf_posarg_width);
ATF_TC_HEAD(snprintf_posarg_width,tc)953fa39ef9Schristos ATF_TC_HEAD(snprintf_posarg_width, tc)
963fa39ef9Schristos {
973fa39ef9Schristos
983fa39ef9Schristos atf_tc_set_md_var(tc, "descr", "test for positional arguments with "
993fa39ef9Schristos "field width");
1003fa39ef9Schristos }
1013fa39ef9Schristos
ATF_TC_BODY(snprintf_posarg_width,tc)1023fa39ef9Schristos ATF_TC_BODY(snprintf_posarg_width, tc)
1033fa39ef9Schristos {
1043fa39ef9Schristos char s[16];
1053fa39ef9Schristos
1063fa39ef9Schristos ATF_CHECK(snprintf(s, sizeof(s), "%1$*2$d", -23, 4) == 4);
1073fa39ef9Schristos ATF_REQUIRE_STREQ(s, " -23");
1083fa39ef9Schristos }
1093fa39ef9Schristos
1103fa39ef9Schristos ATF_TC(snprintf_posarg_error);
ATF_TC_HEAD(snprintf_posarg_error,tc)1113fa39ef9Schristos ATF_TC_HEAD(snprintf_posarg_error, tc)
1123fa39ef9Schristos {
1133fa39ef9Schristos
1143fa39ef9Schristos atf_tc_set_md_var(tc, "descr", "test for positional arguments out "
1153fa39ef9Schristos "of bounds");
1163fa39ef9Schristos }
1173fa39ef9Schristos
ATF_TC_BODY(snprintf_posarg_error,tc)1183fa39ef9Schristos ATF_TC_BODY(snprintf_posarg_error, tc)
1193fa39ef9Schristos {
1203fa39ef9Schristos char s[16], fmt[32];
1213fa39ef9Schristos
1223fa39ef9Schristos snprintf(fmt, sizeof(fmt), "%%%zu$d", SIZE_MAX / sizeof(size_t));
1233fa39ef9Schristos
1243fa39ef9Schristos ATF_CHECK(snprintf(s, sizeof(s), fmt, -23) == -1);
1253fa39ef9Schristos }
1263fa39ef9Schristos
1270eef4e1eSchristos ATF_TC(snprintf_float);
ATF_TC_HEAD(snprintf_float,tc)1280eef4e1eSchristos ATF_TC_HEAD(snprintf_float, tc)
1290eef4e1eSchristos {
1300eef4e1eSchristos
1310eef4e1eSchristos atf_tc_set_md_var(tc, "descr", "test that floating conversions don't"
1320eef4e1eSchristos " leak memory");
1330eef4e1eSchristos }
1340eef4e1eSchristos
ATF_TC_BODY(snprintf_float,tc)1350eef4e1eSchristos ATF_TC_BODY(snprintf_float, tc)
1360eef4e1eSchristos {
1370eef4e1eSchristos union {
1380eef4e1eSchristos double d;
1390eef4e1eSchristos uint64_t bits;
1400eef4e1eSchristos } u;
1410eef4e1eSchristos uint32_t ul, uh;
1420eef4e1eSchristos time_t now;
1430eef4e1eSchristos char buf[1000];
1440eef4e1eSchristos struct rlimit rl;
1450eef4e1eSchristos
1460eef4e1eSchristos rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
1470eef4e1eSchristos ATF_CHECK(setrlimit(RLIMIT_AS, &rl) != -1);
1480eef4e1eSchristos rl.rlim_cur = rl.rlim_max = 1 * 1024 * 1024;
1490eef4e1eSchristos ATF_CHECK(setrlimit(RLIMIT_DATA, &rl) != -1);
1500eef4e1eSchristos
1510eef4e1eSchristos time(&now);
1520eef4e1eSchristos srand(now);
1536c8d572aSjruoho for (size_t i = 0; i < 10000; i++) {
1540eef4e1eSchristos ul = rand();
1550eef4e1eSchristos uh = rand();
1560eef4e1eSchristos u.bits = (uint64_t)uh << 32 | ul;
1570eef4e1eSchristos ATF_CHECK(snprintf(buf, sizeof buf, " %.2f", u.d) != -1);
1580eef4e1eSchristos }
1590eef4e1eSchristos }
1600eef4e1eSchristos
161aa3f9890Sjruoho ATF_TC(sprintf_zeropad);
ATF_TC_HEAD(sprintf_zeropad,tc)162aa3f9890Sjruoho ATF_TC_HEAD(sprintf_zeropad, tc)
163aa3f9890Sjruoho {
1648b18a8bfSjruoho atf_tc_set_md_var(tc, "descr",
1658b18a8bfSjruoho "Test output format zero padding (PR lib/44113)");
166aa3f9890Sjruoho }
167aa3f9890Sjruoho
ATF_TC_BODY(sprintf_zeropad,tc)168aa3f9890Sjruoho ATF_TC_BODY(sprintf_zeropad, tc)
169aa3f9890Sjruoho {
170aa3f9890Sjruoho char str[1024];
171aa3f9890Sjruoho
172aa3f9890Sjruoho ATF_CHECK(sprintf(str, "%010f", 0.0) == 10);
173aa3f9890Sjruoho ATF_REQUIRE_STREQ(str, "000.000000");
174aa3f9890Sjruoho
175aa3f9890Sjruoho /* ieeefp */
176aa3f9890Sjruoho #ifndef __vax__
1778b18a8bfSjruoho /* printf(3) should ignore zero padding for nan/inf */
178aa3f9890Sjruoho ATF_CHECK(sprintf(str, "%010f", NAN) == 10);
179aa3f9890Sjruoho ATF_REQUIRE_STREQ(str, " nan");
180aa3f9890Sjruoho ATF_CHECK(sprintf(str, "%010f", INFINITY) == 10);
181aa3f9890Sjruoho ATF_REQUIRE_STREQ(str, " inf");
182aa3f9890Sjruoho #endif
183aa3f9890Sjruoho }
184aa3f9890Sjruoho
18530cc2417Schristos ATF_TC(snprintf_double_a);
ATF_TC_HEAD(snprintf_double_a,tc)18630cc2417Schristos ATF_TC_HEAD(snprintf_double_a, tc)
18730cc2417Schristos {
18830cc2417Schristos atf_tc_set_md_var(tc, "descr", "Test printf a format");
18930cc2417Schristos }
19030cc2417Schristos
ATF_TC_BODY(snprintf_double_a,tc)19130cc2417Schristos ATF_TC_BODY(snprintf_double_a, tc)
19230cc2417Schristos {
19330cc2417Schristos char buf[1000];
19430cc2417Schristos
19530cc2417Schristos snprintf(buf, sizeof buf, "%.3a", (double)10.6);
1965c6dfe98Sriastradh ATF_CHECK_MSG((strcmp(buf, "0x1.533p+3") == 0 ||
1975c6dfe98Sriastradh strcmp(buf, "0x2.a66p+2") == 0 ||
19827df239dSriastradh strcmp(buf, "0x5.4cdp+1") == 0 ||
19965c3528fSriastradh strcmp(buf, "0xa.99ap+0") == 0),
2005c6dfe98Sriastradh "buf=%s", buf);
2015c6dfe98Sriastradh
2025c6dfe98Sriastradh snprintf(buf, sizeof buf, "%a", (double)0.125);
2035c6dfe98Sriastradh ATF_CHECK_MSG((strcmp(buf, "0x1p-3") == 0 ||
2045c6dfe98Sriastradh strcmp(buf, "0x2p-4") == 0 ||
2055c6dfe98Sriastradh strcmp(buf, "0x4p-5") == 0 ||
2065c6dfe98Sriastradh strcmp(buf, "0x8p-6") == 0),
2075c6dfe98Sriastradh "buf=%s", buf);
2085c6dfe98Sriastradh }
2095c6dfe98Sriastradh
2105c6dfe98Sriastradh ATF_TC(snprintf_long_double_a);
ATF_TC_HEAD(snprintf_long_double_a,tc)2115c6dfe98Sriastradh ATF_TC_HEAD(snprintf_long_double_a, tc)
2125c6dfe98Sriastradh {
2135c6dfe98Sriastradh atf_tc_set_md_var(tc, "descr", "Test printf La format");
2145c6dfe98Sriastradh }
2155c6dfe98Sriastradh
ATF_TC_BODY(snprintf_long_double_a,tc)2165c6dfe98Sriastradh ATF_TC_BODY(snprintf_long_double_a, tc)
2175c6dfe98Sriastradh {
2185c6dfe98Sriastradh char buf[1000];
2195c6dfe98Sriastradh
2205c6dfe98Sriastradh snprintf(buf, sizeof buf, "%.3La", 10.6L);
2215c6dfe98Sriastradh ATF_CHECK_MSG((strcmp(buf, "0x1.533p+3") == 0 ||
2225c6dfe98Sriastradh strcmp(buf, "0x2.a66p+2") == 0 ||
22327df239dSriastradh strcmp(buf, "0x5.4cdp+1") == 0 ||
2241076b20bSriastradh strcmp(buf, "0xa.99ap+0") == 0),
2255c6dfe98Sriastradh "buf=%s", buf);
2265c6dfe98Sriastradh
2275c6dfe98Sriastradh snprintf(buf, sizeof buf, "%La", 0.125L);
2285c6dfe98Sriastradh ATF_CHECK_MSG((strcmp(buf, "0x1p-3") == 0 ||
2295c6dfe98Sriastradh strcmp(buf, "0x2p-4") == 0 ||
2305c6dfe98Sriastradh strcmp(buf, "0x4p-5") == 0 ||
2315c6dfe98Sriastradh strcmp(buf, "0x8p-6") == 0),
2325c6dfe98Sriastradh "buf=%s", buf);
2331252743aSriastradh
234*c5c7b2d6Sriastradh /*
235*c5c7b2d6Sriastradh * Test case adapted from:
236*c5c7b2d6Sriastradh *
237*c5c7b2d6Sriastradh * https://mail-index.netbsd.org/tech-userlevel/2020/04/11/msg012329.html
238*c5c7b2d6Sriastradh */
2391252743aSriastradh #if LDBL_MAX_EXP >= 16384 && LDBL_MANT_DIG >= 64
2401252743aSriastradh snprintf(buf, sizeof buf, "%La", -0xc.ecececececececep+3788L);
2411252743aSriastradh ATF_CHECK_MSG((strcmp(buf, "-0x1.9d9d9d9d9d9d9d9cp+3791") == 0 ||
2421252743aSriastradh strcmp(buf, "-0x3.3b3b3b3b3b3b3b38p+3790") == 0 ||
2431252743aSriastradh strcmp(buf, "-0x6.7676767676767674p+3789") == 0 ||
2441252743aSriastradh strcmp(buf, "-0xc.ecececececececep+3788") == 0),
2451252743aSriastradh "buf=%s", buf);
2461252743aSriastradh #endif
2471252743aSriastradh
2481252743aSriastradh #if LDBL_MAX_EXP >= 16384 && LDBL_MANT_DIG >= 113
2491252743aSriastradh snprintf(buf, sizeof buf, "%La",
250*c5c7b2d6Sriastradh -0x1.cecececececececececececececep+3791L);
2511252743aSriastradh ATF_CHECK_MSG((strcmp(buf,
252da294ec0Sriastradh "-0x1.cecececececececececececececep+3791") == 0 ||
2531252743aSriastradh strcmp(buf, "-0x3.3333333333333338p+3790") == 0 ||
2541252743aSriastradh strcmp(buf, "-0x6.767676767676767p+3789") == 0 ||
2551252743aSriastradh strcmp(buf, "-0xc.ecececececececep+3788") == 0),
2561252743aSriastradh "buf=%s", buf);
2571252743aSriastradh #endif
25830cc2417Schristos }
25930cc2417Schristos
26030cc2417Schristos /* is "long double" and "double" different? */
26130cc2417Schristos #if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
26230cc2417Schristos (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
26330cc2417Schristos #define WIDE_DOUBLE
26430cc2417Schristos #endif
26530cc2417Schristos
26630cc2417Schristos #ifndef WIDE_DOUBLE
26730cc2417Schristos ATF_TC(pr57250_fix);
ATF_TC_HEAD(pr57250_fix,tc)26830cc2417Schristos ATF_TC_HEAD(pr57250_fix, tc)
26930cc2417Schristos {
27030cc2417Schristos atf_tc_set_md_var(tc, "descr", "Test for PR57250");
27130cc2417Schristos }
27230cc2417Schristos
ATF_TC_BODY(pr57250_fix,tc)27330cc2417Schristos ATF_TC_BODY(pr57250_fix, tc)
27430cc2417Schristos {
27530cc2417Schristos char *eptr;
27630cc2417Schristos char buf[1000];
27730cc2417Schristos long double ld;
27830cc2417Schristos
27930cc2417Schristos errno = 0;
28030cc2417Schristos ld = strtold("1e309", &eptr);
28130cc2417Schristos ATF_CHECK(errno != 0);
28230cc2417Schristos ld = (double)ld;
28330cc2417Schristos ATF_CHECK(isfinite(ld) == 0);
28430cc2417Schristos snprintf(buf, sizeof buf, "%Lf\n", ld);
285ac0941c5She ATF_REQUIRE_STREQ(buf, "inf\n");
28630cc2417Schristos }
28730cc2417Schristos #endif
28830cc2417Schristos
28930cc2417Schristos
ATF_TP_ADD_TCS(tp)290aa3f9890Sjruoho ATF_TP_ADD_TCS(tp)
291aa3f9890Sjruoho {
292aa3f9890Sjruoho
293a6bc77fdSjruoho ATF_TP_ADD_TC(tp, snprintf_c99);
294d808fe5fSjruoho ATF_TP_ADD_TC(tp, snprintf_dotzero);
2953fa39ef9Schristos ATF_TP_ADD_TC(tp, snprintf_posarg);
2963fa39ef9Schristos ATF_TP_ADD_TC(tp, snprintf_posarg_width);
2973fa39ef9Schristos ATF_TP_ADD_TC(tp, snprintf_posarg_error);
2980eef4e1eSchristos ATF_TP_ADD_TC(tp, snprintf_float);
299aa3f9890Sjruoho ATF_TP_ADD_TC(tp, sprintf_zeropad);
30030cc2417Schristos ATF_TP_ADD_TC(tp, snprintf_double_a);
3015c6dfe98Sriastradh ATF_TP_ADD_TC(tp, snprintf_long_double_a);
30230cc2417Schristos #ifndef WIDE_DOUBLE
30330cc2417Schristos ATF_TP_ADD_TC(tp, pr57250_fix);
30430cc2417Schristos #endif
305aa3f9890Sjruoho
306aa3f9890Sjruoho return atf_no_error();
307aa3f9890Sjruoho }
308