Re: [PATCH v9 2/9] lib: vsprintf: export simple_strntoull() in a safe prototype
From: Rodrigo Alencar
Date: Mon Mar 30 2026 - 08:50:04 EST
On 26/03/27 03:17PM, Rodrigo Alencar wrote:
> On 26/03/27 12:21PM, Andy Shevchenko wrote:
> > On Fri, Mar 27, 2026 at 10:11:56AM +0000, Rodrigo Alencar wrote:
> > > On 26/03/27 11:17AM, Andy Shevchenko wrote:
> > > > On Fri, Mar 27, 2026 at 09:45:17AM +0100, Petr Mladek wrote:
> > > > > On Fri 2026-03-20 16:27:27, Rodrigo Alencar via B4 Relay wrote:
...
> > > > Maybe we want to have kstrtof32() and kstrtof64() for these two cases?
> > > >
> > > > With that we will always consider the fraction part as 32- or 64-bit,
> > > > imply floor() on the fraction for the sake of simplicity and require
> > > > it to be NUL-terminated with possible trailing '\n'.
> > >
> > > I think this is a good idea, but calling it float or fixed point itself
> > > is a bit confusing as float often refers to the IEEE 754 standard and
> > > fixed point types is often expressed in Q-format.
> >
> > Yeah... I am lack of better naming.
>
> decimals is the name, but they are often represented as:
>
> DECIMAL = INT * 10^X + FRAC
>
> in a single 64-bit number, which would be fine for my end use case.
> However IIO decimal fixed point parsing is out there for quite some time a
> lot of drivers use that. The interface often relies on breaking parsed values
> into an integer array (for standard attributes int val and int val2 are expected).
Thinking about this again and in IIO drivers we end up doing something like:
val64 = (u64)val * MICRO + val2;
so that drivers often work with scaled versions of the decimal value.
then, would it make sense to have a function that already outputs such value?
That would allow to have more freedom over the 64-bit split between integer
and fractional parts.
As a draft:
static int _kstrtodec64(const char *s, unsigned int scale, u64 *res)
{
u64 _res = 0, _frac = 0;
unsigned int rv;
if (*s != '.') {
rv = _parse_integer(s, 10, &_res);
if (rv & KSTRTOX_OVERFLOW)
return -ERANGE;
if (rv == 0)
return -EINVAL;
s += rv;
}
if (*s == '.') {
s++;
rv = _parse_integer_limit(s, 10, &_frac, scale);
if (rv & KSTRTOX_OVERFLOW)
return -ERANGE;
if (rv == 0)
return -EINVAL;
s += rv;
if (rv < scale)
_frac *= int_pow(10, scale - rv);
while (isdigit(*s)) /* truncate */
s++;
}
if (*s == '\n')
s++;
if (*s)
return -EINVAL;
if (check_mul_overflow(_res, int_pow(10, scale), &_res) ||
check_add_overflow(_res, _frac, &_res))
return -ERANGE;
*res = _res;
return 0;
}
noinline
int kstrtoudec64(const char *s, unsigned int scale, u64 *res)
{
if (s[0] == '+')
s++;
return _kstrtodec64(s, scale, res);
}
EXPORT_SYMBOL(kstrtoudec64);
noinline
int kstrtosdec64(const char *s, unsigned int scale, s64 *res)
{
u64 tmp;
int rv;
if (s[0] == '-') {
rv = _kstrtodec64(s + 1, scale, &tmp);
if (rv < 0)
return rv;
if ((s64)-tmp > 0)
return -ERANGE;
*res = -tmp;
} else {
rv = kstrtoudec64(s, scale, &tmp);
if (rv < 0)
return rv;
if ((s64)tmp < 0)
return -ERANGE;
*res = tmp;
}
return 0;
}
EXPORT_SYMBOL(kstrtosdec64);
e.g., kstrtosdec64() or kstrtoudec64() parses "3.1415" with scale 3 into 3141
--
Kind regards,
Rodrigo Alencar