Skip to content

Commit 1757ea3

Browse files
ndrs-pstkartben
authored andcommitted
drivers: sensors: improve range check in sensor_value_from_float/double
Avoid undefined behavior caused by casting floating-point values outside the int32_t range. The updated implementation explicitly validates input bounds before performing conversions, ensuring consistent behavior across platforms. Added test cases to cover edge conditions near float rounding limits and INT32 range boundaries. Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
1 parent 434d022 commit 1757ea3

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

include/zephyr/drivers/sensor.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,18 +1349,15 @@ static inline float sensor_value_to_float(const struct sensor_value *val)
13491349
*/
13501350
static inline int sensor_value_from_double(struct sensor_value *val, double inp)
13511351
{
1352-
if (inp < INT32_MIN || inp > INT32_MAX) {
1352+
if (inp < (double)INT32_MIN || inp > (double)INT32_MAX) {
13531353
return -ERANGE;
13541354
}
13551355

1356-
double val2 = (inp - (int32_t)inp) * 1000000.0;
1356+
int32_t val1 = (int32_t)inp;
1357+
int32_t val2 = (int32_t)((inp - (double)val1) * 1000000.0);
13571358

1358-
if (val2 < INT32_MIN || val2 > INT32_MAX) {
1359-
return -ERANGE;
1360-
}
1361-
1362-
val->val1 = (int32_t)inp;
1363-
val->val2 = (int32_t)val2;
1359+
val->val1 = val1;
1360+
val->val2 = val2;
13641361

13651362
return 0;
13661363
}
@@ -1374,14 +1371,15 @@ static inline int sensor_value_from_double(struct sensor_value *val, double inp)
13741371
*/
13751372
static inline int sensor_value_from_float(struct sensor_value *val, float inp)
13761373
{
1377-
float val2 = (inp - (int32_t)inp) * 1000000.0f;
1378-
1379-
if (val2 < INT32_MIN || val2 > (float)(INT32_MAX - 1)) {
1374+
if (inp < (float)INT32_MIN || inp >= (float)INT32_MAX) {
13801375
return -ERANGE;
13811376
}
13821377

1383-
val->val1 = (int32_t)inp;
1384-
val->val2 = (int32_t)val2;
1378+
int32_t val1 = (int32_t)inp;
1379+
int32_t val2 = (int32_t)((inp - (float)val1) * 1000000.0f);
1380+
1381+
val->val1 = val1;
1382+
val->val2 = val2;
13851383

13861384
return 0;
13871385
}

tests/drivers/sensor/generic/src/main.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,38 @@ ZTEST(sensor_api, test_sensor_unit_conversion)
325325
"the data does not match");
326326
zassert_equal(data.val2, SENSOR_PI%(data.val1 * 1000000LL),
327327
"the data does not match");
328+
329+
/* Extensive tests for edge cases */
330+
int ret;
331+
332+
sensor_value_from_double(&data, -2147483648.0);
333+
zassert_equal(data.val1, -2147483648, "the data does not match");
334+
zassert_equal(data.val2, 0, "the data does not match");
335+
336+
ret = sensor_value_from_double(&data, -2147483649.0);
337+
zassert_equal(ret, -ERANGE, "range error expected");
338+
339+
sensor_value_from_double(&data, 2147483647.0);
340+
zassert_equal(data.val1, 2147483647, "the data does not match");
341+
zassert_equal(data.val2, 0, "the data does not match");
342+
343+
ret = sensor_value_from_double(&data, 2147483648.0);
344+
zassert_equal(ret, -ERANGE, "range error expected");
345+
346+
sensor_value_from_float(&data, -2147483648.0f);
347+
zassert_equal(data.val1, -2147483648, "the data does not match");
348+
zassert_equal(data.val2, 0, "the data does not match");
349+
350+
ret = sensor_value_from_float(&data, -2147483904.0f);
351+
zassert_equal(ret, -ERANGE, "range error expected");
352+
353+
sensor_value_from_float(&data, 2147483520.0f);
354+
zassert_equal(data.val1, 2147483520, "the data does not match");
355+
zassert_equal(data.val2, 0, "the data does not match");
356+
357+
ret = sensor_value_from_float(&data, 2147483584.0f);
358+
zassert_equal(ret, -ERANGE, "range error expected");
359+
328360
#endif
329361
/* reset test data to positive value */
330362
data.val1 = 3;

0 commit comments

Comments
 (0)