diff options
| author | Julian Braha <julianbraha@gmail.com> | 2026-08-30 23:11:29 +0100 |
|---|---|---|
| committer | Nathan Chancellor <nathan@kernel.org> | 2026-09-17 16:19:02 -0700 |
| commit | dbe1ae2304a3b02c3bf6ae82895ff232a29f3fee (patch) | |
| tree | d55b306c8f610afc4f3bc9e1d78d377a0968c9db /scripts | |
| parent | ff87968e4e564acb2fadce363b1b41e7fa3aad2f (diff) | |
| download | linux-next-dbe1ae2304a3b02c3bf6ae82895ff232a29f3fee.tar.gz linux-next-dbe1ae2304a3b02c3bf6ae82895ff232a29f3fee.zip | |
kconfig: fix extra output from savedefconfig on out-of-range defaults
The Kconfig interpreter currently allows defaults that are outside of the
range bounds.
In these cases, the 'sym_validate_range' function will adjust the default
value to the nearest range bound. For example, see this example:
config A
int
range 1 2
default 16
Here, since the default value of 16 is greater than the bounds, the
effective default value gets adjusted down to the upper bound, 2.
However, 'savedefconfig' writes non-default values, and without being
aware of the automatic adjustment to the range bound, it would write: A=2
This limitation is also documented in a comment: "The following fails to
handle the situation where a default value is further limited by the valid
range."
To resolve this, let's factor out the default-range adjustment logic from
the existing 'sym_validate_range' function into its own
'sym_get_near_range_bound' function for 'savedefconfig' to use too, so
that it compares against the effective value.
Adds tests, accordingly.
Fixes: 7cf3d73b4360 ("kconfig: add savedefconfig")
Assisted-by: Codex:gpt-5.6-sol
Reported-by: Geert Uytterhoeven <geert+renesas@glider.be>
Closes: https://lore.kernel.org/lkml/CAMuHMdVyUAA3L4mUkSjmnuE3cvj-+N8z-Bhxsh1wa-FQWc=fjw@mail.gmail.com/
Signed-off-by: Julian Braha <julianbraha@gmail.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Link: https://patch.msgid.link/20260830221129.2668354-1-julianbraha@gmail.com
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/kconfig/symbol.c | 39 | ||||
| -rw-r--r-- | scripts/kconfig/tests/savedefconfig_range/Kconfig | 60 | ||||
| -rw-r--r-- | scripts/kconfig/tests/savedefconfig_range/__init__.py | 8 | ||||
| -rw-r--r-- | scripts/kconfig/tests/savedefconfig_range/config | 7 | ||||
| -rw-r--r-- | scripts/kconfig/tests/savedefconfig_range/expected_defconfig | 0 |
5 files changed, 102 insertions, 12 deletions
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index e82f330fb8ee..01aa58d92c3b 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -157,7 +157,12 @@ static long long sym_get_range_val(struct symbol *sym, int base) return strtoll(sym->curr.val, NULL, base); } -static void sym_validate_range(struct symbol *sym) +/* + * Return the nearest range bound for an out-of-range default value. + * Return NULL if the value is valid or the symbol has no active range. + */ +static struct symbol *sym_get_near_range_bound(struct symbol *sym, + const char *value) { struct property *prop; struct symbol *range_sym; @@ -172,21 +177,31 @@ static void sym_validate_range(struct symbol *sym) base = 16; break; default: - return; + return NULL; } prop = sym_get_range_prop(sym); if (!prop) - return; - val = strtoll(sym->curr.val, NULL, base); + return NULL; + val = strtoll(value, NULL, base); range_sym = prop->expr->left.sym; val2 = sym_get_range_val(range_sym, base); if (val >= val2) { range_sym = prop->expr->right.sym; val2 = sym_get_range_val(range_sym, base); if (val <= val2) - return; + return NULL; } - sym->curr.val = range_sym->curr.val; + + return range_sym; +} + +static void sym_validate_range(struct symbol *sym) +{ + struct symbol *range_sym; + + range_sym = sym_get_near_range_bound(sym, sym->curr.val); + if (range_sym) + sym->curr.val = range_sym->curr.val; } static void sym_set_changed(struct symbol *sym) @@ -812,7 +827,7 @@ bool sym_set_string_value(struct symbol *sym, const char *newval) const char *sym_get_string_default(struct symbol *sym) { struct property *prop; - struct symbol *ds; + struct symbol *ds, *range_sym; const char *str = ""; tristate val; @@ -830,11 +845,6 @@ const char *sym_get_string_default(struct symbol *sym) val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); break; default: - /* - * The following fails to handle the situation - * where a default value is further limited by - * the valid range. - */ ds = prop_get_symbol(prop); if (ds != NULL) { sym_calc_value(ds); @@ -878,6 +888,11 @@ const char *sym_get_string_default(struct symbol *sym) default: break; } + + range_sym = sym_get_near_range_bound(sym, str); + if (range_sym) + str = range_sym->curr.val; + return str; } diff --git a/scripts/kconfig/tests/savedefconfig_range/Kconfig b/scripts/kconfig/tests/savedefconfig_range/Kconfig new file mode 100644 index 000000000000..fd59d9082ed5 --- /dev/null +++ b/scripts/kconfig/tests/savedefconfig_range/Kconfig @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Static default and range values + +config INT_DEFAULT_ABOVE_RANGE + int + range 1 1 + default 16 + +config INT_DEFAULT_BELOW_RANGE + int + range 4 8 + default 2 + +# Default and range values determined by other options + +config RANGE_UPPER_BOUND + int + default 3 + +config INT_DYNAMIC_RANGE + int + range 0 RANGE_UPPER_BOUND + default 4 + +# Hex + +config HEX_DEFAULT_ABOVE_RANGE + hex + range 0x10 0x20 + default 0x40 + +# Implicit default value of 0 + +config INT_IMPLICIT_DEFAULT_ZERO + int + range 1 4 + +# Conditional range + +config USE_FIRST_RANGE + bool + default y + +config INT_CONDITIONAL_RANGE + int + range 1 2 if USE_FIRST_RANGE + range 3 4 if !USE_FIRST_RANGE + default 3 + +# Conditional default + +config USE_DEFAULT + bool + default y + +config INT_CONDITIONAL_DEFAULT + int + range 1 2 + default 3 if USE_DEFAULT diff --git a/scripts/kconfig/tests/savedefconfig_range/__init__.py b/scripts/kconfig/tests/savedefconfig_range/__init__.py new file mode 100644 index 000000000000..961454be732c --- /dev/null +++ b/scripts/kconfig/tests/savedefconfig_range/__init__.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +"""Test savedefconfig with numerical defaults outside of ranges.""" + + +def test(conf): + assert conf._run_conf('--savedefconfig=defconfig', dot_config='config', + out_file='defconfig') == 0 + assert conf.config_matches('expected_defconfig') diff --git a/scripts/kconfig/tests/savedefconfig_range/config b/scripts/kconfig/tests/savedefconfig_range/config new file mode 100644 index 000000000000..d939cfe5fd34 --- /dev/null +++ b/scripts/kconfig/tests/savedefconfig_range/config @@ -0,0 +1,7 @@ +CONFIG_INT_DEFAULT_ABOVE_RANGE=1 +CONFIG_INT_DEFAULT_BELOW_RANGE=4 +CONFIG_INT_DYNAMIC_RANGE=3 +CONFIG_HEX_DEFAULT_ABOVE_RANGE=0x20 +CONFIG_INT_IMPLICIT_DEFAULT_ZERO=1 +CONFIG_INT_CONDITIONAL_RANGE=2 +CONFIG_INT_CONDITIONAL_DEFAULT=2 diff --git a/scripts/kconfig/tests/savedefconfig_range/expected_defconfig b/scripts/kconfig/tests/savedefconfig_range/expected_defconfig new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/scripts/kconfig/tests/savedefconfig_range/expected_defconfig |
