kconfig: loop as long as we changed some symbols in randconfig

Because of choice-in-a-choice constructs, it can happen that not all
symbols are assigned a value during randconfig, leading in rare cases
to this situation:

    ---8<--- choice-in-choice.in
    choice
        bool "A/B/C"
    config A
        bool "A"

    config B
        bool "B"
    if B
    choice
        bool "E/F"
    config E
        bool "E"
    config F
        bool "F"
    endchoice
    endif # B

    config C
        bool "C"
    endchoice
    ---8<---

    $ ./scripts/kconfig/conf --randconfig choice-in-choice.in
    [--SNIP--]
    $ ./scripts/kconfig/conf --silentoldconfig choice-in-choice.in </dev/null
    [--SNIP--]
    A/B/C
      1. A (A)
    > 2. B (B)
      3. C (C)
    choice[1-3]: 2
      E/F
      > 1. E (E) (NEW)
        2. F (F) (NEW)
      choice[1-2]: aborted!

    Console input/output is redirected. Run 'make oldconfig' to update
    configuration.

Fix this by looping in randconfig for as long as some symbol gets assigned
a value.

Note: this was spotted with the USB EHCI Debug Device Gadget (USB_G_DBGP),
which uses this choice-in-a-choice construct, and exhibits this problem.
The example above is just a stripped-down minimalist test-case.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
This commit is contained in:
Yann E. MORIN 2013-04-28 22:36:38 +02:00
parent a1ce636f56
commit 3b9a19e089
3 changed files with 17 additions and 6 deletions

View File

@ -654,7 +654,8 @@ int main(int ac, char **av)
conf_set_all_new_symbols(def_default); conf_set_all_new_symbols(def_default);
break; break;
case randconfig: case randconfig:
conf_set_all_new_symbols(def_random); /* Really nothing to do in this loop */
while (conf_set_all_new_symbols(def_random)) ;
break; break;
case defconfig: case defconfig:
conf_set_all_new_symbols(def_default); conf_set_all_new_symbols(def_default);

View File

@ -1040,7 +1040,7 @@ void conf_set_changed_callback(void (*fn)(void))
conf_changed_callback = fn; conf_changed_callback = fn;
} }
static void randomize_choice_values(struct symbol *csym) static bool randomize_choice_values(struct symbol *csym)
{ {
struct property *prop; struct property *prop;
struct symbol *sym; struct symbol *sym;
@ -1053,7 +1053,7 @@ static void randomize_choice_values(struct symbol *csym)
* In both cases stop. * In both cases stop.
*/ */
if (csym->curr.tri != yes) if (csym->curr.tri != yes)
return; return false;
prop = sym_get_choice_prop(csym); prop = sym_get_choice_prop(csym);
@ -1084,6 +1084,8 @@ static void randomize_choice_values(struct symbol *csym)
csym->flags |= SYMBOL_DEF_USER; csym->flags |= SYMBOL_DEF_USER;
/* clear VALID to get value calculated */ /* clear VALID to get value calculated */
csym->flags &= ~(SYMBOL_VALID); csym->flags &= ~(SYMBOL_VALID);
return true;
} }
void set_all_choice_values(struct symbol *csym) void set_all_choice_values(struct symbol *csym)
@ -1106,7 +1108,7 @@ void set_all_choice_values(struct symbol *csym)
csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
} }
void conf_set_all_new_symbols(enum conf_def_mode mode) bool conf_set_all_new_symbols(enum conf_def_mode mode)
{ {
struct symbol *sym, *csym; struct symbol *sym, *csym;
int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y
@ -1154,6 +1156,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
exit( 1 ); exit( 1 );
} }
} }
bool has_changed = false;
for_all_symbols(i, sym) { for_all_symbols(i, sym) {
if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
@ -1161,6 +1164,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
switch (sym_get_type(sym)) { switch (sym_get_type(sym)) {
case S_BOOLEAN: case S_BOOLEAN:
case S_TRISTATE: case S_TRISTATE:
has_changed = true;
switch (mode) { switch (mode) {
case def_yes: case def_yes:
sym->def[S_DEF_USER].tri = yes; sym->def[S_DEF_USER].tri = yes;
@ -1219,6 +1223,12 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
sym_calc_value(csym); sym_calc_value(csym);
if (mode == def_random) if (mode == def_random)
randomize_choice_values(csym); has_changed = randomize_choice_values(csym);
else {
set_all_choice_values(csym);
has_changed = true;
}
} }
return has_changed;
} }

View File

@ -86,7 +86,7 @@ const char *conf_get_autoconfig_name(void);
char *conf_get_default_confname(void); char *conf_get_default_confname(void);
void sym_set_change_count(int count); void sym_set_change_count(int count);
void sym_add_change_count(int count); void sym_add_change_count(int count);
void conf_set_all_new_symbols(enum conf_def_mode mode); bool conf_set_all_new_symbols(enum conf_def_mode mode);
void set_all_choice_values(struct symbol *csym); void set_all_choice_values(struct symbol *csym);
struct conf_printer { struct conf_printer {