From nobody Sun Sep 14 04:53:51 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cPbR356pBz67KGJ; Sun, 14 Sep 2025 04:53:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cPbR33gS3z3SGP; Sun, 14 Sep 2025 04:53:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1757825631; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kfWws+gajaCu+SLvfegk29UJ0ECtYX7yaW9/3FKpjJU=; b=gGBJ6JWcS89j+Pntss+lVkSFjkw30VBO6fNJGzz1IzcTND8TOwT5UZHjxgqzVDdMcTesX6 Wgi2kjdgUI9kHLjgTAuT+IMpwnde0N8VV91BMtB2bgMSWXWXFwe95v4jFrKVS501teVIWD XC5vewk0B5LwgyIUqP71K++fJy96/OgJIIm6k7e0gwQ7dyV4nIia8rVG72gQrpvKQqlN6n NHqJNdIZ5hXSbO83bMdjQ6rmSFQdKfxJ//nY30Dq9l7553WsVqONG1KCkE+EDjy3CHSq3q kFhgj63Fn/0dl6b1b+UCqNgAo5CQERLOnsIWxAzGjrE2tpXeaFSXB3m854tkMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1757825631; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kfWws+gajaCu+SLvfegk29UJ0ECtYX7yaW9/3FKpjJU=; b=LBzBAuZKUcJ64JgBtyCA2En3Jcu7kETEI3PQx2XdPRFAYbHVEgFaqHeXd6ZnlW55NcF+Zc KWwjTrgXCm93bYdYh6+KXZXtKOYbbxkvUqEMcHS9DL6bT5lCKcngDiCXSOxRRwhRyjtxRi xyoNgDuvRpGZBEcSYtnE+vuepPlIp37iu7E0TbB+HqhoHJeqR8XC4Jdw95zv2ML71sGLCl cU8aNxiy+RcVaKQQ8XukBLzxfQ26aLzuogu74XUcGw++38ivb2NMS8lb7eS70Nmdm9bPNn wOsbSlaJRHt/WY2cl8DzE7ZWuN827DKcYFz5ENOP/uu2t2q5mRQWbHi+eYd7Nw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1757825631; a=rsa-sha256; cv=none; b=RXJbZueJ6jub4l8ZOe6xNNQfPLEmqfS8g5x5o1D2acYGDUTSxutbRij5mFFfPEbXuQXU58 HqBd5m1BWN92ok7T+SXQIkeENyJjxDQ8c+NoLupg3PMono6ROyBhRzGVZ72R3vZ3TuDkNo eCl2AVfjmyX4eRqHwgrzXUYXzKFnpuQ9P924bJ9yJue6afHs99fXLDb3MPU0OI04TnAxTe s6+qeQrpl3b0t8Q6wTLK2yAq/gqX+VsUngqlujEyVFA8OnxK4RqpgfWNhmMdWzsvenNk/g yYIDqrDbX6jAKZ2a1pTxfK2PqKcQaJX39dMUk+bGwYvnw6EFCN5TFre1N2ZAqQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cPbR330Fpz19H4; Sun, 14 Sep 2025 04:53:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 58E4rpof036414; Sun, 14 Sep 2025 04:53:51 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 58E4rpFF036411; Sun, 14 Sep 2025 04:53:51 GMT (envelope-from git) Date: Sun, 14 Sep 2025 04:53:51 GMT Message-Id: <202509140453.58E4rpFF036411@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Warner Losh Subject: git: 9dd78db9c30a - main - libc: prevent incorrect %a/%La rounding at full precision List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9dd78db9c30a220ac3e8e65d89548ff99c14dd90 Auto-Submitted: auto-generated The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=9dd78db9c30a220ac3e8e65d89548ff99c14dd90 commit 9dd78db9c30a220ac3e8e65d89548ff99c14dd90 Author: Osamu Sho AuthorDate: 2025-09-04 02:34:34 +0000 Commit: Warner Losh CommitDate: 2025-09-14 03:09:26 +0000 libc: prevent incorrect %a/%La rounding at full precision In __hdtoa() and __hldtoa(), rounding is incorrectly applied when the requested precision exactly matches the number of significant hexadecimal digits. In this case, the redux adjustment can trigger an unintended exponent increment and shift the rounding position left by one bit. This causes the least significant digit to be rounded incorrectly. The fix adds a new condition based on MAX_HEX_DIGITS (derived from MANT_DIG) so that rounding is performed only when precision is strictly less than the number of significant digits. This avoids the unintended shift while preserving correct rounding for other cases. A new regression test (printfloat_test:hexadecimal_rounding_offset_eq_exp) covers both the binary64 (%.13a) and binary128 (%.28La on arm64) cases that previously fail, ensuring the bug does not regress. Note: MAX_HEX_DIGITS represents the maximum number of hexadecimal digits needed to express the mantissa. It is computed by subtracting the implicit integer bit from [L]DBL_MANT_DIG, dividing the remaining mantissa bits by 4 (with +3 to round up any remainder), and finally adding +1 for the leading integer digit. This makes its meaning explicit and distinct from SIGFIGS, which serves a different purpose. Fixes: 76303a9735ee ("Make several changes to the way printf handles hex floating point (%a):") Signed-off-by: Osamu Sho Reviewed by: imp,jlduran Pull Request: https://github.com/freebsd/freebsd-src/pull/1837 --- lib/libc/gdtoa/_hdtoa.c | 3 ++- lib/libc/gdtoa/_hldtoa.c | 3 ++- lib/libc/tests/stdio/printfloat_test.c | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/libc/gdtoa/_hdtoa.c b/lib/libc/gdtoa/_hdtoa.c index 8ae739acf0db..9c42630cd918 100644 --- a/lib/libc/gdtoa/_hdtoa.c +++ b/lib/libc/gdtoa/_hdtoa.c @@ -40,6 +40,7 @@ #define DBL_ADJ (DBL_MAX_EXP - 2) #define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1) +#define MAX_HEX_DIGITS ((DBL_MANT_DIG + 3 - 1) / 4 + 1) static const float one[] = { 1.0f, -1.0f }; @@ -111,7 +112,7 @@ __hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, s0 = rv_alloc(bufsize); /* Round to the desired number of digits. */ - if (SIGFIGS > ndigits && ndigits > 0) { + if (MAX_HEX_DIGITS > ndigits && ndigits > 0) { float redux = one[u.bits.sign]; int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG; u.bits.exp = offset; diff --git a/lib/libc/gdtoa/_hldtoa.c b/lib/libc/gdtoa/_hldtoa.c index 965d2349d103..5f10d12c5c09 100644 --- a/lib/libc/gdtoa/_hldtoa.c +++ b/lib/libc/gdtoa/_hldtoa.c @@ -65,6 +65,7 @@ typedef uint32_t manl_t; #define LDBL_ADJ (LDBL_MAX_EXP - 2) #define SIGFIGS ((LDBL_MANT_DIG + 3) / 4 + 1) +#define MAX_HEX_DIGITS ((LDBL_MANT_DIG + 3 - 1) / 4 + 1) static const float one[] = { 1.0f, -1.0f }; @@ -125,7 +126,7 @@ __hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign, s0 = rv_alloc(bufsize); /* Round to the desired number of digits. */ - if (SIGFIGS > ndigits && ndigits > 0) { + if (MAX_HEX_DIGITS > ndigits && ndigits > 0) { float redux = one[u.bits.sign]; int offset = 4 * ndigits + LDBL_MAX_EXP - 4 - LDBL_MANT_DIG; #ifdef __i386__ diff --git a/lib/libc/tests/stdio/printfloat_test.c b/lib/libc/tests/stdio/printfloat_test.c index 031859124163..795c7797541e 100644 --- a/lib/libc/tests/stdio/printfloat_test.c +++ b/lib/libc/tests/stdio/printfloat_test.c @@ -398,6 +398,18 @@ ATF_TC_BODY(subnormal_float, tc) testfmt("-0X1P-149", "%A", negative); } +ATF_TC_WITHOUT_HEAD(hexadecimal_rounding_fullprec); +ATF_TC_BODY(hexadecimal_rounding_fullprec, tc) +{ + /* Double: %.13a with binary64 mantissa=53 */ + testfmt("0x1.1234567890bbbp+0", "%.13a", 0x1.1234567890bbbp + 0); + +#if defined(__aarch64__) + /* On arm64, long double is IEEE binary128 (mantissa=113) */ + testfmt("0x1.3c0ca428c59fbbbbbbbbbbbbbbbbp+0", "%.28La", 0x1.3c0ca428c59fbbbbbbbbbbbbbbbbp + 0L); +#endif +} + ATF_TP_ADD_TCS(tp) { @@ -414,6 +426,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, hexadecimal_rounding); ATF_TP_ADD_TC(tp, subnormal_double); ATF_TP_ADD_TC(tp, subnormal_float); + ATF_TP_ADD_TC(tp, hexadecimal_rounding_fullprec); return (atf_no_error()); }