|
|
Message-ID: <20260805130937.GA3542221@port70.net>
Date: Wed, 5 Aug 2026 15:09:37 +0200
From: Szabolcs Nagy <nsz@...t70.net>
To: Matthias Goergens <matthias.goergens@...il.com>
Cc: musl@...ts.openwall.com
Subject: Re: [PATCH] stdio: reserve leading limb for floating-point
rounding
* Matthias Goergens <matthias.goergens@...il.com> [2026-08-05 15:52:36 +0800]:
> In the negative-exponent path of floating-point formatting, a value
> just below one can round up to one. The logical layout then starts at
> big[0], so propagating the final rounding carry would form and
> dereference a pointer one element before the array. One reachable case
> is printf("%.0Lf", nextafterl(1.0L, 0.0L)).
i don't see big[-1] deref on x86_64 with that printf
although i'm not sure which deref you talk about
i assumed *d or *a in
/* Decide whether to round by probing round+small */
if (round+small != round) {
*d = *d + i;
while (*d > 999999999) {
*d--=0;
if (d<a) *--a=0;
(*d)++;
}
...
but that looks ok to me (a = d = big+1, big[0] = 0 before the while)
>
> Reserve one physical leading limb and start the negative-exponent
> layout at big+1, leaving big[0] for the single rounding carry. The
> carry cannot need a second new limb: insertion increments a zero limb
> to one and terminates. The positive-exponent layout is computed from
> the enlarged array end, so its distances to both array ends are
> unchanged and all logical pointer differences used by formatting are
> preserved.
>
> Formatted output is unchanged: the 62,304-case corpus and the extrema
> matrices are byte-identical before and after, on all three musl
> long-double representations (x87 64-bit mantissa, 53-bit, and
> binary128).
> ---
> src/stdio/vfprintf.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
> index 514a44dd..bfbcf094 100644
> --- a/src/stdio/vfprintf.c
> +++ b/src/stdio/vfprintf.c
> @@ -182,11 +182,12 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t, int ps)
> {
> int max_mant_dig = (ps==BIGLPRE) ? LDBL_MANT_DIG : DBL_MANT_DIG;
> int max_exp = (ps==BIGLPRE) ? LDBL_MAX_EXP : DBL_MAX_EXP;
> - /* One slot for 29 bits left of radix point, a slot for every 29-21=8
> - * bits right of the radix point, and one final zero slot. */
> + /* One slot for a rounding carry, one for 29 bits left of radix point,
> + * a slot for every 29-21=8 bits right of the radix point, and one final
> + * zero slot. */
> int max_mant_slots = 1 + (max_mant_dig-29+7)/8 + 1;
> int max_exp_slots = (max_exp+max_mant_dig+28+8)/9;
> - int bufsize = max_mant_slots + max_exp_slots;
> + int bufsize = 1 + max_mant_slots + max_exp_slots;
> uint32_t big[bufsize];
> uint32_t *a, *d, *r, *z;
> int e2=0, e, i, j, l;
> @@ -267,7 +268,7 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t, int ps)
>
> if (y) y *= 0x1p28, e2-=28;
>
> - if (e2<0) a=r=z=big;
> + if (e2<0) a=r=z=big+1;
> else a=r=z=big+sizeof(big)/sizeof(*big) - max_mant_slots - 1;
>
> do {
> --
> 2.55.0
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.