[PATCH v2 5/5] kconfig: use unsigned integers for hex range checks

From: Julian Braha

Date: Tue Sep 15 2026 - 17:20:36 EST


While 'hex' values should use the bounds of 64-bit unsigned integers, the
range values are treated as signed (checks use strtoll).

For example:

config HEX_RANGE
hex
range 0 0xfffffffffffffffe
default 0xffffffffffffffff

the default value should adjust down to the upper bound of
0xfffffffffffffffe, but since the check incorrectly parses both as
LLONG_MAX, the value stays at the out-of-range default of
0xffffffffffffffff.

To fix this, let's use a union of signed and unsigned integers to
represent both 'int' and 'hex' range values, then use both strtoll and
strtoull where appropriate.

Assisted-by: LLM
Signed-off-by: Julian Braha <julianbraha@xxxxxxxxx>
---
scripts/kconfig/symbol.c | 41 ++++++++++++++-----
.../kconfig/tests/warn_changed_input/Kconfig | 5 +++
.../tests/warn_changed_input/expected_config | 1 +
3 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 0b3d19af269f..14b029f9d6df 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -142,8 +142,15 @@ struct property *sym_get_range_prop(struct symbol *sym)
return NULL;
}

-static long long sym_get_range_val(struct symbol *sym, int base)
+union range_value {
+ long long s;
+ unsigned long long u;
+};
+
+static union range_value sym_get_range_val(struct symbol *sym, int base)
{
+ union range_value val;
+
sym_calc_value(sym);
switch (sym->type) {
case S_INT:
@@ -155,7 +162,12 @@ static long long sym_get_range_val(struct symbol *sym, int base)
default:
break;
}
- return strtoll(sym->curr.val, NULL, base);
+ if (base == 10)
+ val.s = strtoll(sym->curr.val, NULL, base);
+ else
+ /* HEX */
+ val.u = strtoull(sym->curr.val, NULL, base);
+ return val;
}

static void sym_validate_range(struct symbol *sym)
@@ -163,7 +175,7 @@ static void sym_validate_range(struct symbol *sym)
struct property *prop;
struct symbol *range_sym;
int base;
- long long val, val2;
+ union range_value val, val2;

switch (sym->type) {
case S_INT:
@@ -178,13 +190,19 @@ static void sym_validate_range(struct symbol *sym)
prop = sym_get_range_prop(sym);
if (!prop)
return;
- val = strtoll(sym->curr.val, NULL, base);
+ val = sym_get_range_val(sym, base);
range_sym = prop->expr->left.sym;
val2 = sym_get_range_val(range_sym, base);
- if (val >= val2) {
+
+ if (base == 10 && val.s >= val2.s) {
+ range_sym = prop->expr->right.sym;
+ val2 = sym_get_range_val(range_sym, base);
+ if (val.s <= val2.s)
+ return;
+ } else if (base == 16 && val.u >= val2.u) {
range_sym = prop->expr->right.sym;
val2 = sym_get_range_val(range_sym, base);
- if (val <= val2)
+ if (val.u <= val2.u)
return;
}
sym->curr.val = range_sym->curr.val;
@@ -731,6 +749,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
{
struct property *prop;
long long val;
+ unsigned long long uval;

switch (sym->type) {
case S_STRING:
@@ -744,8 +763,8 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
if (!prop)
return true;
val = strtoll(str, NULL, 10);
- return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
- val <= sym_get_range_val(prop->expr->right.sym, 10);
+ return val >= sym_get_range_val(prop->expr->left.sym, 10).s &&
+ val <= sym_get_range_val(prop->expr->right.sym, 10).s;
case S_HEX:
if (!sym_string_valid(sym, str))
return false;
@@ -754,9 +773,9 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
prop = sym_get_range_prop(sym);
if (!prop)
return true;
- val = strtoll(str, NULL, 16);
- return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
- val <= sym_get_range_val(prop->expr->right.sym, 16);
+ uval = strtoull(str, NULL, 16);
+ return uval >= sym_get_range_val(prop->expr->left.sym, 16).u &&
+ uval <= sym_get_range_val(prop->expr->right.sym, 16).u;
case S_BOOLEAN:
case S_TRISTATE:
switch (str[0]) {
diff --git a/scripts/kconfig/tests/warn_changed_input/Kconfig b/scripts/kconfig/tests/warn_changed_input/Kconfig
index 69845e2f3fb3..df4183a08420 100644
--- a/scripts/kconfig/tests/warn_changed_input/Kconfig
+++ b/scripts/kconfig/tests/warn_changed_input/Kconfig
@@ -26,6 +26,11 @@ config NUM
Kconfig resolves it to the constrained in-range value.
The warning should report that adjustment.

+config HEX_RANGE
+ hex
+ range 0 0xfffffffffffffffe
+ default 0xffffffffffffffff
+
config DUP
bool "DUP"
depends on DEP
diff --git a/scripts/kconfig/tests/warn_changed_input/expected_config b/scripts/kconfig/tests/warn_changed_input/expected_config
index fe8bbec66c53..6a8d98a69b7e 100644
--- a/scripts/kconfig/tests/warn_changed_input/expected_config
+++ b/scripts/kconfig/tests/warn_changed_input/expected_config
@@ -4,3 +4,4 @@
#
# CONFIG_DEP is not set
CONFIG_NUM=20
+CONFIG_HEX_RANGE=0xfffffffffffffffe
--
2.55.0