Kconfig currently doesn't handle 'm' appearing in a Kconfig file before
the modules symbol is defined (the symbol with 'option modules'). The
problem is the following code, which runs during parsing:

        /* change 'm' into 'm' && MODULES */
        if (e->left.sym == &symbol_mod)
                return expr_alloc_and(e, expr_alloc_symbol(modules_sym));

If the modules symbol has not yet been defined, modules_sym is NULL,
giving an invalid expression.

Here is a test file where both BEFORE_1 and BEFORE_2 trigger a segfault.
If the modules symbol is removed, all symbols trigger segfaults.

        config BEFORE_1
                def_tristate y if m

        if m
        config BEFORE_2
                def_tristate y
        endif

        config MODULES
                def_bool y
                option modules

        config AFTER_1
                def_tristate y if m

        if m
        config AFTER_2
                def_tristate y
        endif

Fix the issue by rewriting 'm' in menu_finalize() instead. This function
runs after parsing and is the proper place to do it. The following
existing code in conf_parse() in zconf.y ensures that the modules symbol
exists at that point:

        if (!modules_sym)
                modules_sym = sym_find( "n" );

        ...

        menu_finalize(&rootmenu);

The following tests were done to ensure no functional changes for
configurations that don't reference 'm' before the modules symbol:

        - zconfdump(stdout) was run with ARCH=x86 and ARCH=arm before
          and after the change and verified to produce identical output.
          This function prints all symbols, choices, and menus together
          with their properties and their dependency expressions. A
          rewritten 'm' appears as 'm && MODULES'.

          A small annoyance is that the assert(len != 0) in xfwrite()
          needs to be disabled in order to use zconfdump(), because it
          chokes on e.g. 'default ""'.

        - The Kconfiglib test suite was run to indirectly verify that
          alldefconfig, allyesconfig, allnoconfig, and all defconfigs in
          the kernel still generate the same final .config.

        - Valgrind was used to check for memory errors and (new) memory
          leaks.

Signed-off-by: Ulf Magnusson <ulfali...@gmail.com>
---
 scripts/kconfig/menu.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 94f192de..a7396e4 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -110,7 +110,7 @@ static struct expr *rewrite_m(struct expr *e)
 
 void menu_add_dep(struct expr *dep)
 {
-       current_entry->dep = expr_alloc_and(current_entry->dep, rewrite_m(dep));
+       current_entry->dep = expr_alloc_and(current_entry->dep, dep);
 }
 
 void menu_set_type(int type)
@@ -135,7 +135,7 @@ static struct property *menu_add_prop(enum prop_type type, 
char *prompt, struct
 
        prop->menu = current_entry;
        prop->expr = expr;
-       prop->visible.expr = rewrite_m(dep);
+       prop->visible.expr = dep;
 
        if (prompt) {
                if (isspace(*prompt)) {
@@ -330,7 +330,8 @@ void menu_finalize(struct menu *parent)
                         * Propagate parent dependencies to the child menu
                         * node, also rewriting and simplifying expressions
                         */
-                       basedep = expr_transform(menu->dep);
+                       basedep = rewrite_m(menu->dep);
+                       basedep = expr_transform(basedep);
                        basedep = expr_alloc_and(expr_copy(parentdep), basedep);
                        basedep = expr_eliminate_dups(basedep);
                        menu->dep = basedep;
@@ -373,7 +374,8 @@ void menu_finalize(struct menu *parent)
                                 * property's condition, rewriting and
                                 * simplifying expressions at the same time
                                 */
-                               dep = expr_transform(prop->visible.expr);
+                               dep = rewrite_m(prop->visible.expr);
+                               dep = expr_transform(dep);
                                dep = expr_alloc_and(expr_copy(basedep), dep);
                                dep = expr_eliminate_dups(dep);
                                if (menu->sym && menu->sym->type != S_TRISTATE)
-- 
2.7.4

Reply via email to