[PATCH v3 1/4] iio: prepare iio_format_value to handle higher-precision IIO_VAL_DECIMAL64_* formats
From: Victor Chernyakin
Date: Mon Oct 26 2026 - 12:57:15 EST
Prepare iio_format_value for an upcoming patch that adds formats up
to IIO_VAL_DECIMAL64_YOCTO (a scale of 24 digits) by avoiding
computing 10^scale when doing so would overflow, and by avoiding
undefined behavior due to abs(LLONG_MIN) (which couldn't happen
previously).
Signed-off-by: Victor Chernyakin <chernyakin.victor.j@xxxxxxxxxxx>
---
drivers/iio/industrialio-core.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 767a7794624a..c30659ca0544 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -653,6 +653,18 @@ int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix)
}
EXPORT_SYMBOL(iio_read_mount_matrix);
+/*
+ * Regular abs(LLONG_MIN) causes signed overflow, which is undefined
+ * behavior. This variant avoids that by performing the computation in an
+ * unsigned type, for which negation is always well-defined.
+ */
+static inline u64 abs_s64_no_overflow(s64 x)
+{
+ return x < 0 ? -(u64)x : (u64)x;
+}
+
+#define GREATEST_POWER_OF_10_THAT_FITS_IN_S64 18
+
static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
int size, const int *vals)
{
@@ -720,13 +732,19 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
int scale = type - IIO_VAL_DECIMAL64_BASE;
s64 frac;
- tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]),
- int_pow(10, scale), &frac);
+ if (scale <= GREATEST_POWER_OF_10_THAT_FITS_IN_S64) {
+ tmp2 = div64_s64_rem(iio_val_s64_compose(vals[0], vals[1]),
+ int_pow(10, scale), &frac);
+ } else {
+ tmp2 = 0;
+ frac = iio_val_s64_compose(vals[0], vals[1]);
+ }
+
if (tmp2 == 0 && frac < 0)
l += sysfs_emit_at(buf, offset, "-");
- l += sysfs_emit_at(buf, offset + l, "%lld.%0*lld", tmp2, scale,
- abs(frac));
+ l += sysfs_emit_at(buf, offset + l, "%lld.%0*llu", tmp2, scale,
+ abs_s64_no_overflow(frac));
return l;
}
default:
--
2.53.0