diff mbox

kconfig/menu.c: fix multiple references to expressions in menu_add_prop()

Message ID 1369126451-11930-1-git-send-email-dirk@gouders.net (mailing list archive)
State New, archived
Headers show

Commit Message

Dirk Gouders May 21, 2013, 8:54 a.m. UTC
menu_add_prop() applies upper menus' visibilities to actual prompts
by AND-ing the prompts visibilities with the upper menus ones.

This creates a further reference to the menu's visibilities and when
the expression reduction functions do their work, they may remove or
modify expressions that have multiple references, thus causing
unpredictable side-effects.

The following example Kconfig constructs a case where this causes
problems: a menu and a prompt which's visibilities depend on the same
symbol.  When invoking mconf with this Kconfig and pressing "Z" we
see a problem caused by a free'd expression still referenced by the
menu's visibility:

------------------------------------------------------------------------
mainmenu "Kconfig Testing Configuration"

config VISIBLE
	def_bool n

config Placeholder
	bool "Place holder"

menu "Invisible"
	visible if VISIBLE

config TEST_VAR
	bool "Test option" if VISIBLE

endmenu
------------------------------------------------------------------------

This patch fixes this problem by creating copies of the menu's
visibility expressions before AND-ing them with the prompt's one.

Signed-off-by: Dirk Gouders <dirk@gouders.net>
---
 scripts/kconfig/menu.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

Comments

Dirk Gouders May 21, 2013, 12:36 p.m. UTC | #1
CCing the original author of the code (commit 7ad1227818f09 "kconfig:
fix undesirable side effect of adding "visible" menu attribute").

Dirk

Dirk Gouders <dirk@gouders.net> writes:

> menu_add_prop() applies upper menus' visibilities to actual prompts
> by AND-ing the prompts visibilities with the upper menus ones.
>
> This creates a further reference to the menu's visibilities and when
> the expression reduction functions do their work, they may remove or
> modify expressions that have multiple references, thus causing
> unpredictable side-effects.
>
> The following example Kconfig constructs a case where this causes
> problems: a menu and a prompt which's visibilities depend on the same
> symbol.  When invoking mconf with this Kconfig and pressing "Z" we
> see a problem caused by a free'd expression still referenced by the
> menu's visibility:
>
> ------------------------------------------------------------------------
> mainmenu "Kconfig Testing Configuration"
>
> config VISIBLE
> 	def_bool n
>
> config Placeholder
> 	bool "Place holder"
>
> menu "Invisible"
> 	visible if VISIBLE
>
> config TEST_VAR
> 	bool "Test option" if VISIBLE
>
> endmenu
> ------------------------------------------------------------------------
>
> This patch fixes this problem by creating copies of the menu's
> visibility expressions before AND-ing them with the prompt's one.
>
> Signed-off-by: Dirk Gouders <dirk@gouders.net>
> ---
>  scripts/kconfig/menu.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
> index b5c7d90..567939c 100644
> --- a/scripts/kconfig/menu.c
> +++ b/scripts/kconfig/menu.c
> @@ -143,14 +143,25 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
>  
>  		/* Apply all upper menus' visibilities to actual prompts. */
>  		if(type == P_PROMPT) {
> +			struct expr *dup_expr;
>  			struct menu *menu = current_entry;
>  
>  			while ((menu = menu->parent) != NULL) {
>  				if (!menu->visibility)
>  					continue;
> +				/*
> +				 * Do not add a reference to the
> +				 * menu's visibility expression but
> +				 * use a copy of it.  Otherwise the
> +				 * expression reduction functions
> +				 * will modify expressions that have
> +				 * multiple references which can
> +				 * cause unwanted side-effects.
> +				 */
> +				dup_expr = expr_copy(menu->visibility);
> +
>  				prop->visible.expr
> -					= expr_alloc_and(prop->visible.expr,
> -							 menu->visibility);
> +					= expr_alloc_and(prop->visible.expr, dup_expr);
>  			}
>  		}
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yann E. MORIN May 23, 2013, 8:28 a.m. UTC | #2
Dirk, All,

On 2013-05-21 10:54 +0200, Dirk Gouders spake thusly:
> menu_add_prop() applies upper menus' visibilities to actual prompts
> by AND-ing the prompts visibilities with the upper menus ones.
[--SNIP--]
> This patch fixes this problem by creating copies of the menu's
> visibility expressions before AND-ing them with the prompt's one.
> 
> Signed-off-by: Dirk Gouders <dirk@gouders.net>
> ---
>  scripts/kconfig/menu.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
> index b5c7d90..567939c 100644
> --- a/scripts/kconfig/menu.c
> +++ b/scripts/kconfig/menu.c
> @@ -143,14 +143,25 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
>  
>  		/* Apply all upper menus' visibilities to actual prompts. */
>  		if(type == P_PROMPT) {
> +			struct expr *dup_expr;

I'd rather this variable defined below:

>  			struct menu *menu = current_entry;
>  
>  			while ((menu = menu->parent) != NULL) {

... here, in the block where it is used, since it is not relevant
outside this block.

>  				if (!menu->visibility)
>  					continue;
> +				/*
> +				 * Do not add a reference to the
> +				 * menu's visibility expression but
> +				 * use a copy of it.  Otherwise the
> +				 * expression reduction functions
> +				 * will modify expressions that have
> +				 * multiple references which can
> +				 * cause unwanted side-effects.
> +				 */
> +				dup_expr = expr_copy(menu->visibility);

I wonder if/where this should be de-allocated.

> +
>  				prop->visible.expr
> -					= expr_alloc_and(prop->visible.expr,
> -							 menu->visibility);
> +					= expr_alloc_and(prop->visible.expr, dup_expr);
>  			}
>  		}
>  

I'm testing it right now. Thanks!

Regards,
Yann E. MORIN.
Dirk Gouders May 23, 2013, 10:25 a.m. UTC | #3
Thanks for reviewing and testing a patch of mine, again, Yann.


"Yann E. MORIN" <yann.morin.1998@free.fr> writes:

> Dirk, All,
>
> On 2013-05-21 10:54 +0200, Dirk Gouders spake thusly:
>> menu_add_prop() applies upper menus' visibilities to actual prompts
>> by AND-ing the prompts visibilities with the upper menus ones.
> [--SNIP--]
>> This patch fixes this problem by creating copies of the menu's
>> visibility expressions before AND-ing them with the prompt's one.
>> 
>> Signed-off-by: Dirk Gouders <dirk@gouders.net>
>> ---
>>  scripts/kconfig/menu.c | 15 +++++++++++++--
>>  1 file changed, 13 insertions(+), 2 deletions(-)
>> 
>> diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
>> index b5c7d90..567939c 100644
>> --- a/scripts/kconfig/menu.c
>> +++ b/scripts/kconfig/menu.c
>> @@ -143,14 +143,25 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
>>  
>>  		/* Apply all upper menus' visibilities to actual prompts. */
>>  		if(type == P_PROMPT) {
>> +			struct expr *dup_expr;
>
> I'd rather this variable defined below:
>
>>  			struct menu *menu = current_entry;
>>  
>>  			while ((menu = menu->parent) != NULL) {
>
> ... here, in the block where it is used, since it is not relevant
> outside this block.

Indeed, I will fix this.
I also noticed that I should fix some spelling (e.g. side effect instead
of side-effect).  I hope it is OK, to wait for your tests before sending
a v2.

>>  				if (!menu->visibility)
>>  					continue;
>> +				/*
>> +				 * Do not add a reference to the
>> +				 * menu's visibility expression but
>> +				 * use a copy of it.  Otherwise the
>> +				 * expression reduction functions
>> +				 * will modify expressions that have
>> +				 * multiple references which can
>> +				 * cause unwanted side-effects.
>> +				 */
>> +				dup_expr = expr_copy(menu->visibility);
>
> I wonder if/where this should be de-allocated.

Actually, I did not find any piece of code that systematically free()s
the allocated data structures and I also think that it would be good to
have such code, because that would have caused double-free()s and
therfore noticed us immediately when we create multiple references to
expressions.

My plan was, to first to fix this single problem and then take care for
a larger review of dynamically allocated memory.

I tested mconf for example with valgrind and the next thing I planned to
suggest is to make the kconfig code mostly "valgrind-clean".  But I
expect this to become a rather extensive change and would like to hear
if others also think it should be done.

>
>> +
>>  				prop->visible.expr
>> -					= expr_alloc_and(prop->visible.expr,
>> -							 menu->visibility);
>> +					= expr_alloc_and(prop->visible.expr, dup_expr);
>>  			}
>>  		}
>>  
>
> I'm testing it right now. Thanks!

Again, thanks for spending the time.

Dirk

> Regards,
> Yann E. MORIN.
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yann E. MORIN May 29, 2013, 9:58 p.m. UTC | #4
Dirk, All,

On 2013-05-23 12:25 +0200, Dirk Gouders spake thusly:
> "Yann E. MORIN" <yann.morin.1998@free.fr> writes:
> > On 2013-05-21 10:54 +0200, Dirk Gouders spake thusly:
> >> menu_add_prop() applies upper menus' visibilities to actual prompts
> >> by AND-ing the prompts visibilities with the upper menus ones.
> > [--SNIP--]
> >> This patch fixes this problem by creating copies of the menu's
> >> visibility expressions before AND-ing them with the prompt's one.
[--SNIP--]
> >> --- a/scripts/kconfig/menu.c
> >> +++ b/scripts/kconfig/menu.c
> >> @@ -143,14 +143,25 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
> >>  
> >>  		/* Apply all upper menus' visibilities to actual prompts. */
> >>  		if(type == P_PROMPT) {
> >> +			struct expr *dup_expr;
> >
> > I'd rather this variable defined below:
> >
> >>  			struct menu *menu = current_entry;
> >>  
> >>  			while ((menu = menu->parent) != NULL) {
> >
> > ... here, in the block where it is used, since it is not relevant
> > outside this block.
> 
> Indeed, I will fix this.
> I also noticed that I should fix some spelling (e.g. side effect instead
> of side-effect).  I hope it is OK, to wait for your tests before sending
> a v2.

If you're speaking about typoes in your patch, I'll just fix them here
(along with the variable move above), don't worry.

If you're speaking about typoes in the rest of the code, then please
submit a separate patch.

> >>  				if (!menu->visibility)
> >>  					continue;
> >> +				/*
> >> +				 * Do not add a reference to the
> >> +				 * menu's visibility expression but
> >> +				 * use a copy of it.  Otherwise the
> >> +				 * expression reduction functions
> >> +				 * will modify expressions that have
> >> +				 * multiple references which can
> >> +				 * cause unwanted side-effects.
> >> +				 */
> >> +				dup_expr = expr_copy(menu->visibility);
> >
> > I wonder if/where this should be de-allocated.
> 
> Actually, I did not find any piece of code that systematically free()s
> the allocated data structures

Indeed.
My question was a bit rhetorical.

> and I also think that it would be good to
> have such code, because that would have caused double-free()s and
> therfore noticed us immediately when we create multiple references to
> expressions.
> 
> My plan was, to first to fix this single problem and then take care for
> a larger review of dynamically allocated memory.

Yes, that would be awesome! :-)

> I tested mconf for example with valgrind and the next thing I planned to
> suggest is to make the kconfig code mostly "valgrind-clean".  But I
> expect this to become a rather extensive change and would like to hear
> if others also think it should be done.

Although a little bit of memory leak in kconfig is no big issue for the
kernel tree (since the frontends are rather short-lived programs), other
users of kconfig may use long-lived processes that would suffer from
memory leaks.

Fixing those would be a net gain, I believe.

Regards,
Yann E. MORIN.
Dirk Gouders May 30, 2013, 3:59 a.m. UTC | #5
"Yann E. MORIN" <yann.morin.1998@free.fr> writes:

> Dirk, All,
>
> On 2013-05-23 12:25 +0200, Dirk Gouders spake thusly:
>> "Yann E. MORIN" <yann.morin.1998@free.fr> writes:
>> > On 2013-05-21 10:54 +0200, Dirk Gouders spake thusly:
>> >> menu_add_prop() applies upper menus' visibilities to actual prompts
>> >> by AND-ing the prompts visibilities with the upper menus ones.
>> > [--SNIP--]
>> >> This patch fixes this problem by creating copies of the menu's
>> >> visibility expressions before AND-ing them with the prompt's one.
> [--SNIP--]
>> >> --- a/scripts/kconfig/menu.c
>> >> +++ b/scripts/kconfig/menu.c
>> >> @@ -143,14 +143,25 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
>> >>  
>> >>  		/* Apply all upper menus' visibilities to actual prompts. */
>> >>  		if(type == P_PROMPT) {
>> >> +			struct expr *dup_expr;
>> >
>> > I'd rather this variable defined below:
>> >
>> >>  			struct menu *menu = current_entry;
>> >>  
>> >>  			while ((menu = menu->parent) != NULL) {
>> >
>> > ... here, in the block where it is used, since it is not relevant
>> > outside this block.
>> 
>> Indeed, I will fix this.
>> I also noticed that I should fix some spelling (e.g. side effect instead
>> of side-effect).  I hope it is OK, to wait for your tests before sending
>> a v2.
>
> If you're speaking about typoes in your patch, I'll just fix them here
> (along with the variable move above), don't worry.

Thanks for fixing all that.

[SNIP]
>> Actually, I did not find any piece of code that systematically free()s
>> the allocated data structures
>
> Indeed.
> My question was a bit rhetorical.
>
>> and I also think that it would be good to
>> have such code, because that would have caused double-free()s and
>> therfore noticed us immediately when we create multiple references to
>> expressions.
>> 
>> My plan was, to first to fix this single problem and then take care for
>> a larger review of dynamically allocated memory.
>
> Yes, that would be awesome! :-)
>
>> I tested mconf for example with valgrind and the next thing I planned to
>> suggest is to make the kconfig code mostly "valgrind-clean".  But I
>> expect this to become a rather extensive change and would like to hear
>> if others also think it should be done.
>
> Although a little bit of memory leak in kconfig is no big issue for the
> kernel tree (since the frontends are rather short-lived programs), other
> users of kconfig may use long-lived processes that would suffer from
> memory leaks.
>
> Fixing those would be a net gain, I believe.

OK, I already started to care for a clean heap when mconf exits and
make good progress but there are still some bytes left ;-) -- and more
references to free'd expressions, I'm afraid.

I am planning to put these changes in multiple simple commits (so that
later possible bisecting will point to mainly one or few line changes)
and send them to you for review if that is OK to you.

Dirk
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index b5c7d90..567939c 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -143,14 +143,25 @@  struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
 
 		/* Apply all upper menus' visibilities to actual prompts. */
 		if(type == P_PROMPT) {
+			struct expr *dup_expr;
 			struct menu *menu = current_entry;
 
 			while ((menu = menu->parent) != NULL) {
 				if (!menu->visibility)
 					continue;
+				/*
+				 * Do not add a reference to the
+				 * menu's visibility expression but
+				 * use a copy of it.  Otherwise the
+				 * expression reduction functions
+				 * will modify expressions that have
+				 * multiple references which can
+				 * cause unwanted side-effects.
+				 */
+				dup_expr = expr_copy(menu->visibility);
+
 				prop->visible.expr
-					= expr_alloc_and(prop->visible.expr,
-							 menu->visibility);
+					= expr_alloc_and(prop->visible.expr, dup_expr);
 			}
 		}