Re: [PATCH v3 1/3] iio: light: isl29018: fix overflow and precision in isl29018_read_lux()
From: Andy Shevchenko
Date: Thu Jun 04 2026 - 16:26:23 EST
On Thu, Jun 04, 2026 at 12:06:15PM +0200, Herman van Hazendonk wrote:
> The intermediate calculations in isl29018_read_lux() use 32-bit
> arithmetic throughout, which overflows in two distinct ways:
>
> 1. lux_data * chip->scale.uscale — at 16-bit integration time and the
> 1000 fc range, scale.uscale is 976562. A full-scale 16-bit reading
> (65535) gives 65535 * 976562 ≈ 64 billion, far beyond UINT_MAX.
> The value wraps before the /1000000 division can save it, producing
> a wildly wrong data_x_range.
>
> 2. data_x_range * chip->calibscale — even after a correct data_x_range,
> multiplying by a calibscale of a few hundred (reasonable for a deeply
> tinted cover glass) pushes the product past INT_MAX, causing *lux to
> wrap negative.
>
> Additionally, dividing lux_data * scale.uscale by 1000000 before
> applying calibscale discards the fractional-lux remainder. For low
> ranges where scale.scale is zero, any reading below 1000000/scale.uscale
> counts truncates to a data_x_range of zero, so the calibscale
> multiplication cannot rescue it. This creates a dead-band at low light
> levels that is especially visible when a large cover-glass compensation
> gain is in use.
>
> Fix the overflows by widening the intermediate variables to u64 and
> using div_u64() for the divisions (plain 64-bit division emits
> __aeabi_uldivmod on ARM32, which is not available in kernel builds).
> Preserve the uscale remainder across the first division so that the
> calibscale multiplication captures the sub-lux contribution. Clamp
> the final result to INT_MAX before storing it in the signed int *lux
> out parameter.
...
> - unsigned int data_x_range;
> + u32 uscale_rem;
> + u64 uscale_term, data_x_range, result;
Please, try to keep reversed xmas tree order.
...
> + *lux = (int)min_t(u64, result, INT_MAX);
Too many castings. What you most likely want here is clamp(), try never use
min_t().
--
With Best Regards,
Andy Shevchenko