diff options
| author | Alexey Charkov <alchark@flipper.net> | 2026-07-30 22:40:39 +0400 |
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2026-08-11 12:48:50 -0600 |
| commit | c81dbcc9cef01c31f7d6f3da07130cdf4f3ec63a (patch) | |
| tree | 341de14bc3b39576d043217b4d4e9b39e19d96e0 /lib | |
| parent | 8e82c0a75f5df98df1b23d0898c4d7008ab64621 (diff) | |
| download | u-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.c | 7 |
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; |
