Message ID | 20240519092227.2101109-1-masahiroy@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | kconfig: fix comparison to constant symbols, 'm', 'n' | expand |
On Sun, May 19, 2024 at 6:22 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > > Currently, comparisons to 'm' or 'n' result in incorrect output. > > [Test Code] > > config MODULES > def_bool y > modules > > config A > def_tristate m > > config B > def_bool A > n > > CONFIG_B is actually unset, while the expectation is CONFIG_B=y. > > The reason for the issue is because Kconfig compares the tristate values > as strings. > > Currently, the .type fields of the constant symbols, 'y', 'm', and 'n' > are unspecified, i.e., S_UNKNOWN. > > When expr_calc_value() evaluates 'A > n', it checks the types of 'A' and > 'n' to determine how to compare them. > > The left-hand side, 'A', is a tristate symbol with a value of 'm', which > corresponds to a numeric value of 1. (Internally, 'y', 'm', and 'n' are > represented as 2, 1, and 0, respectively.) > > The right-hand side, 'n', has an unknown type, so it is treated as the > string "n" during the comparison. > > expr_calc_value() compares two values numerically only when both can > have numeric values. Otherwise, they are compared as strings. > > symbol numeric value ASCII code > ------------------------------------- > y 2 0x79 > m 1 0x6d > n 0 0x6e > > 'm' is greater than 'n' if compared numerically (since 1 is greater > than 0), but small than 'n' if compared as strings (since the ASCII > code 0x6d is smaller than 0x6e). > > Specifying .type=S_TRISTATE for symbol_{yes,mod,no} fixes the above > test code. > > However, this would cause a regression to the following test code. > > [Test Code 2] > > config MODULES > def_bool n > modules > > config A > def_tristate n > > config B > def_bool A = m > > You would get CONFIG_B=y, while CONFIG_B should not be set. > > The reason is because sym_get_string_value() turns 'm' into 'n' when > the module feature is disabled. Consequently, expr_calc_value() returns > the result of 'A = n' instead of 'A = m'. This oddity has been hidden > because the type of 'm' was previously S_UNKNOWN instead of S_TRISTATE. > > sym_get_string_value() should not tweak the string because the tristate > value has already been correctly calculated. There is no reason to > return the string "n" where its tristate value is mod. > > Signed-off-by: Masahiro Yamada <masahiroy@kernel.org> > --- Fixes: 31847b67bec0 ("kconfig: allow use of relations other than (in)equality")
On Sun, May 19, 2024 at 6:22 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > > Currently, comparisons to 'm' or 'n' result in incorrect output. > > [Test Code] > > config MODULES > def_bool y > modules > > config A > def_tristate m > > config B > def_bool A > n > > CONFIG_B is actually unset, while the expectation is CONFIG_B=y. > > The reason for the issue is because Kconfig compares the tristate values > as strings. > > Currently, the .type fields of the constant symbols, 'y', 'm', and 'n' > are unspecified, i.e., S_UNKNOWN. > > When expr_calc_value() evaluates 'A > n', it checks the types of 'A' and > 'n' to determine how to compare them. > > The left-hand side, 'A', is a tristate symbol with a value of 'm', which > corresponds to a numeric value of 1. (Internally, 'y', 'm', and 'n' are > represented as 2, 1, and 0, respectively.) > > The right-hand side, 'n', has an unknown type, so it is treated as the > string "n" during the comparison. > > expr_calc_value() compares two values numerically only when both can > have numeric values. Otherwise, they are compared as strings. > > symbol numeric value ASCII code > ------------------------------------- > y 2 0x79 > m 1 0x6d > n 0 0x6e > > 'm' is greater than 'n' if compared numerically (since 1 is greater > than 0), but small than 'n' if compared as strings (since the ASCII small than -> smaller than
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index aa0e25ee5119..0e439d3d48d1 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -14,6 +14,7 @@ struct symbol symbol_yes = { .name = "y", + .type = S_TRISTATE, .curr = { "y", yes }, .menus = LIST_HEAD_INIT(symbol_yes.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, @@ -21,6 +22,7 @@ struct symbol symbol_yes = { struct symbol symbol_mod = { .name = "m", + .type = S_TRISTATE, .curr = { "m", mod }, .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, @@ -28,6 +30,7 @@ struct symbol symbol_mod = { struct symbol symbol_no = { .name = "n", + .type = S_TRISTATE, .curr = { "n", no }, .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, @@ -820,8 +823,7 @@ const char *sym_get_string_value(struct symbol *sym) case no: return "n"; case mod: - sym_calc_value(modules_sym); - return (modules_sym->curr.tri == no) ? "n" : "m"; + return "m"; case yes: return "y"; }
Currently, comparisons to 'm' or 'n' result in incorrect output. [Test Code] config MODULES def_bool y modules config A def_tristate m config B def_bool A > n CONFIG_B is actually unset, while the expectation is CONFIG_B=y. The reason for the issue is because Kconfig compares the tristate values as strings. Currently, the .type fields of the constant symbols, 'y', 'm', and 'n' are unspecified, i.e., S_UNKNOWN. When expr_calc_value() evaluates 'A > n', it checks the types of 'A' and 'n' to determine how to compare them. The left-hand side, 'A', is a tristate symbol with a value of 'm', which corresponds to a numeric value of 1. (Internally, 'y', 'm', and 'n' are represented as 2, 1, and 0, respectively.) The right-hand side, 'n', has an unknown type, so it is treated as the string "n" during the comparison. expr_calc_value() compares two values numerically only when both can have numeric values. Otherwise, they are compared as strings. symbol numeric value ASCII code ------------------------------------- y 2 0x79 m 1 0x6d n 0 0x6e 'm' is greater than 'n' if compared numerically (since 1 is greater than 0), but small than 'n' if compared as strings (since the ASCII code 0x6d is smaller than 0x6e). Specifying .type=S_TRISTATE for symbol_{yes,mod,no} fixes the above test code. However, this would cause a regression to the following test code. [Test Code 2] config MODULES def_bool n modules config A def_tristate n config B def_bool A = m You would get CONFIG_B=y, while CONFIG_B should not be set. The reason is because sym_get_string_value() turns 'm' into 'n' when the module feature is disabled. Consequently, expr_calc_value() returns the result of 'A = n' instead of 'A = m'. This oddity has been hidden because the type of 'm' was previously S_UNKNOWN instead of S_TRISTATE. sym_get_string_value() should not tweak the string because the tristate value has already been correctly calculated. There is no reason to return the string "n" where its tristate value is mod. Signed-off-by: Masahiro Yamada <masahiroy@kernel.org> --- scripts/kconfig/symbol.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)