From d044eb659ea7cea14d8004512a7ba9008d5a24bb Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 8 May 2025 12:21:06 +0000 Subject: [PATCH] math: Fix UB in ldbl-128ibm llroundl --- sysdeps/ieee754/ldbl-128ibm/s_lroundl.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c index c357bb0972..57eaeb9562 100644 --- a/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c +++ b/sysdeps/ieee754/ldbl-128ibm/s_lroundl.c @@ -23,12 +23,20 @@ #include #include #include +#include + +static inline bool +check_sign (unsigned long int v1, unsigned long int v2) +{ + enum { sign_shift = sizeof (unsigned long int) * CHAR_BIT - 1 }; + return (v1 & (1UL << sign_shift)) == (v2 & (1UL << sign_shift)); +} long __lroundl (long double x) { double xh, xl; - long res, hi, lo; + long res, hi, lo, tmp; ldbl_unpack (x, &xh, &xl); @@ -84,7 +92,7 @@ __lroundl (long double x) res = (long int) ((unsigned long int) hi + (unsigned long int) lo); /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ - if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) + if (__glibc_unlikely (check_sign (hi, lo) && !check_sign (res, hi))) goto overflow; xh -= lo; @@ -93,24 +101,25 @@ __lroundl (long double x) hi = res; if (xh > 0.5) { - res += 1UL; + INT_ADD_WRAPV (res, 1, &res); } else if (xh == 0.5) { if (xl > 0.0 || (xl == 0.0 && res >= 0)) - res += 1UL; + INT_ADD_WRAPV (res, 1, &res); } else if (-xh > 0.5) { - res -= 1UL; + INT_SUBTRACT_WRAPV (res, 1UL, &res); } else if (-xh == 0.5) { if (xl < 0.0 || (xl == 0.0 && res <= 0)) - res -= 1UL; + INT_SUBTRACT_WRAPV (res, 1UL, &res); } - if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) + INT_SUBTRACT_WRAPV (res, hi, &tmp); + if (__glibc_unlikely (check_sign (hi, tmp) && !check_sign (res, hi))) goto overflow; return res; -- 2.47.2