summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlexey Charkov <alchark@flipper.net>2026-07-30 22:40:39 +0400
committerTom Rini <trini@konsulko.com>2026-08-11 12:48:50 -0600
commitc81dbcc9cef01c31f7d6f3da07130cdf4f3ec63a (patch)
tree341de14bc3b39576d043217b4d4e9b39e19d96e0 /lib
parent8e82c0a75f5df98df1b23d0898c4d7008ab64621 (diff)
downloadu-boot-c81dbcc9cef01c31f7d6f3da07130cdf4f3ec63a.tar.gz
u-boot-c81dbcc9cef01c31f7d6f3da07130cdf4f3ec63a.zip
lib: div64: use abs64() for the 64-bit operands of div64_s64()
Both operands of div64_s64() are s64, but U-Boot's abs() is not 64-bit safe. Unlike its Linux counterpart, which dispatches on the argument type down to long long, U-Boot's abs() evaluates its argument as int whenever sizeof(x) != sizeof(long) and yields a long. The header even says so: "abs() should not be used for 64-bit types (s64, u64, long long) - use abs64() for those." So on BITS_PER_LONG == 32 both operands are silently truncated to 32 bits before the division. Simulating the macro with long narrowed to 32 bits shows what reaches div64_u64(): x= -4294967296 abs()= 0 abs64()= 4294967296 x= -5000000000 abs()= 705032704 abs64()= 5000000000 x=-9223372036854775807 abs()= 1 abs64()= 9223372036854775807 A zero from the first case makes the subsequent division a divide by zero rather than merely imprecise. div64_s64() has no in-tree callers today, so this is a latent bug and not a regression. Note that the abs() in div_s64_rem() is correct as-is and deliberately left alone. Fixes: 0342e335ba88 ("lib: div64: sync with Linux") Signed-off-by: Alexey Charkov <alchark@flipper.net> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/div64.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/lib/div64.c b/lib/div64.c
index 14d402ce4c7..f5624279086 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -171,7 +171,12 @@ s64 div64_s64(s64 dividend, s64 divisor)
{
s64 quot, t;
- quot = div64_u64(abs(dividend), abs(divisor));
+ /*
+ * Unlike Linux, U-Boot's abs() is not 64-bit safe: it evaluates its
+ * argument as int when sizeof(x) != sizeof(long), so both operands
+ * need abs64() here.
+ */
+ quot = div64_u64(abs64(dividend), abs64(divisor));
t = (dividend ^ divisor) >> 63;
return (quot ^ t) - t;