parse-util: fix ineffective overflow guards in store_loadavg_fixed_point()

This commit is contained in:
Armaan Sandhu
2026-09-13 20:27:13 -04:00
parent 5698092294
commit efdc4b0cc7
2 changed files with 29 additions and 6 deletions
+22
View File
@@ -7,6 +7,8 @@
#include "capability-util.h"
#include "locale-util.h"
#include "parse-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "tests.h"
TEST(parse_boolean) {
@@ -864,6 +866,26 @@ TEST(parse_loadavg_fixed_point) {
ASSERT_ERROR(parse_loadavg_fixed_point("4096.4096", &fp), ERANGE);
ASSERT_ERROR(parse_loadavg_fixed_point("-4000.5", &fp), ERANGE);
ASSERT_ERROR(parse_loadavg_fixed_point("18446744073709551615.5", &fp), ERANGE);
/* Neither part may be large enough to overflow the shift by LOADAVG_PRECISION_BITS. Derive the
* boundary from the width of unsigned long, so that this holds on 32 bit too: the largest integer
* part that still fits is ~0UL >> LOADAVG_PRECISION_BITS (2^53-1 on 64 bit), and one more than
* that used to shift clean out of the word and be reported as a load of zero. */
unsigned long max_side = ~0UL >> LOADAVG_PRECISION_BITS;
char buf[DECIMAL_STR_MAX(unsigned long) + STRLEN(".99")];
xsprintf(buf, "%lu.99", max_side);
ASSERT_OK_ZERO(parse_loadavg_fixed_point(buf, &fp));
ASSERT_EQ(LOADAVG_INT_SIDE(fp), max_side);
ASSERT_EQ(LOADAVG_DECIMAL_SIDE(fp), 99U);
xsprintf(buf, "%lu.00", max_side + 1);
ASSERT_ERROR(parse_loadavg_fixed_point(buf, &fp), ERANGE);
/* Same for the fractional part, which used to be shifted before it was range checked. */
xsprintf(buf, "1.%lu", max_side + 1);
ASSERT_ERROR(parse_loadavg_fixed_point(buf, &fp), ERANGE);
ASSERT_ERROR(parse_loadavg_fixed_point("foobar", &fp), EINVAL);
ASSERT_ERROR(parse_loadavg_fixed_point("3333", &fp), EINVAL);
ASSERT_ERROR(parse_loadavg_fixed_point("1.2.3", &fp), EINVAL);