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 42ATF_TC(snprintf_c99); 43ATF_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 50ATF_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 63ATF_TC(snprintf_dotzero); 64ATF_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 71ATF_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 79ATF_TC(snprintf_posarg); 80ATF_TC_HEAD(snprintf_posarg, tc) 81{ 82 83 atf_tc_set_md_var(tc, "descr", "test for positional arguments"); 84} 85 86ATF_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 94ATF_TC(snprintf_posarg_width); 95ATF_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 102ATF_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 110ATF_TC(snprintf_posarg_error); 111ATF_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 118ATF_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 127ATF_TC(snprintf_float); 128ATF_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 135ATF_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 161ATF_TC(sprintf_zeropad); 162ATF_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 168ATF_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 185ATF_TC(snprintf_double_a); 186ATF_TC_HEAD(snprintf_double_a, tc) 187{ 188 atf_tc_set_md_var(tc, "descr", "Test printf a format"); 189} 190 191ATF_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 210ATF_TC(snprintf_long_double_a); 211ATF_TC_HEAD(snprintf_long_double_a, tc) 212{ 213 atf_tc_set_md_var(tc, "descr", "Test printf La format"); 214} 215 216ATF_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 267ATF_TC(pr57250_fix); 268ATF_TC_HEAD(pr57250_fix, tc) 269{ 270 atf_tc_set_md_var(tc, "descr", "Test for PR57250"); 271} 272 273ATF_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 290ATF_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