aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/kconfig/expr.c
diff options
context:
space:
mode:
authorMartin Walch <walch.martin@web.de>2015-05-22 07:41:52 -0400
committerMichal Marek <mmarek@suse.cz>2015-05-25 04:04:12 -0400
commite911503085ae8a6bb826588076f66df05890253c (patch)
treeda8e0feca4c5fa65c0ae57d6bf8e6b5461bc1b5b /scripts/kconfig/expr.c
parentb787f68c36d49bb1d9236f403813641efa74a031 (diff)
Kconfig: Remove bad inference rules expr_eliminate_dups2()
expr_eliminate_dups2() in scripts/kconfig/expr.c applies two invalid inference rules: (FOO || BAR) && (!FOO && !BAR) -> n (FOO && BAR) || (!FOO || !BAR) -> y They would be correct in propositional logic, but this is a three-valued logic, and here it is wrong in that it changes semantics. It becomes immediately visible when assigning the value 1 to both, FOO and BAR: (FOO || BAR) && (!FOO && !BAR) -> min(max(1, 1), min(2-1, 2-1)) = min(1, 1) = 1 while n evaluates to 0 and (FOO && BAR) || (!FOO || !BAR) -> max(min(1, 1), max(2-1, 2-1)) = max(1, 1) = 1 with y evaluating to 2. Fix it by removing expr_eliminate_dups2() and the functions that have no use anywhere else: expr_extract_eq_and(), expr_extract_eq_or(), and expr_extract_eq() from scripts/kconfig/expr.c Currently the bug is not triggered in mainline, so this patch does not modify the configuration space there. To observe the bug consider this example: config MODULES def_bool y option modules config FOO def_tristate m config BAR def_tristate m config TEST1 def_tristate y depends on (FOO || BAR) && (!FOO && !BAR) if TEST1 = n comment "TEST1 broken" endif config TEST2 def_tristate y depends on (FOO && BAR) || (!FOO || !BAR) if TEST2 = y comment "TEST2 broken" endif config TEST3 def_tristate y depends on m && !m if TEST3 = n comment "TEST3 broken" endif TEST1, TEST2 and TEST3 should all evaluate to m, but without the patch, none of them does. It is probably not obvious that TEST3 is the same bug, but it becomes clear when considering what happens internally to the expression m && !m": First it expands to (m && MODULES) && !(m && MODULES), then it is transformed into (m && MODULES) && (!m || !MODULES), and finally due to the bug it is replaced with n. As a side effect, this patch reduces code size in expr.c by roughly 10% and slightly improves startup time for all configuration frontends. Signed-off-by: Martin Walch <walch.martin@web.de> Signed-off-by: Michal Marek <mmarek@suse.cz>
Diffstat (limited to 'scripts/kconfig/expr.c')
-rw-r--r--scripts/kconfig/expr.c111
1 files changed, 0 insertions, 111 deletions
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index fb0a2a286dca..0d7364ce9132 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -13,9 +13,6 @@
13 13
14static int expr_eq(struct expr *e1, struct expr *e2); 14static int expr_eq(struct expr *e1, struct expr *e2);
15static struct expr *expr_eliminate_yn(struct expr *e); 15static struct expr *expr_eliminate_yn(struct expr *e);
16static struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
17static struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
18static void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
19 16
20struct expr *expr_alloc_symbol(struct symbol *sym) 17struct expr *expr_alloc_symbol(struct symbol *sym)
21{ 18{
@@ -559,62 +556,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct
559#undef e2 556#undef e2
560} 557}
561 558
562static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
563{
564#define e1 (*ep1)
565#define e2 (*ep2)
566 struct expr *tmp, *tmp1, *tmp2;
567
568 if (e1->type == type) {
569 expr_eliminate_dups2(type, &e1->left.expr, &e2);
570 expr_eliminate_dups2(type, &e1->right.expr, &e2);
571 return;
572 }
573 if (e2->type == type) {
574 expr_eliminate_dups2(type, &e1, &e2->left.expr);
575 expr_eliminate_dups2(type, &e1, &e2->right.expr);
576 }
577 if (e1 == e2)
578 return;
579
580 switch (e1->type) {
581 case E_OR:
582 expr_eliminate_dups2(e1->type, &e1, &e1);
583 // (FOO || BAR) && (!FOO && !BAR) -> n
584 tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
585 tmp2 = expr_copy(e2);
586 tmp = expr_extract_eq_and(&tmp1, &tmp2);
587 if (expr_is_yes(tmp1)) {
588 expr_free(e1);
589 e1 = expr_alloc_symbol(&symbol_no);
590 trans_count++;
591 }
592 expr_free(tmp2);
593 expr_free(tmp1);
594 expr_free(tmp);
595 break;
596 case E_AND:
597 expr_eliminate_dups2(e1->type, &e1, &e1);
598 // (FOO && BAR) || (!FOO || !BAR) -> y
599 tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
600 tmp2 = expr_copy(e2);
601 tmp = expr_extract_eq_or(&tmp1, &tmp2);
602 if (expr_is_no(tmp1)) {
603 expr_free(e1);
604 e1 = expr_alloc_symbol(&symbol_yes);
605 trans_count++;
606 }
607 expr_free(tmp2);
608 expr_free(tmp1);
609 expr_free(tmp);
610 break;
611 default:
612 ;
613 }
614#undef e1
615#undef e2
616}
617
618struct expr *expr_eliminate_dups(struct expr *e) 559struct expr *expr_eliminate_dups(struct expr *e)
619{ 560{
620 int oldcount; 561 int oldcount;
@@ -627,7 +568,6 @@ struct expr *expr_eliminate_dups(struct expr *e)
627 switch (e->type) { 568 switch (e->type) {
628 case E_OR: case E_AND: 569 case E_OR: case E_AND:
629 expr_eliminate_dups1(e->type, &e, &e); 570 expr_eliminate_dups1(e->type, &e, &e);
630 expr_eliminate_dups2(e->type, &e, &e);
631 default: 571 default:
632 ; 572 ;
633 } 573 }
@@ -829,57 +769,6 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
829 return false; 769 return false;
830} 770}
831 771
832static struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
833{
834 struct expr *tmp = NULL;
835 expr_extract_eq(E_AND, &tmp, ep1, ep2);
836 if (tmp) {
837 *ep1 = expr_eliminate_yn(*ep1);
838 *ep2 = expr_eliminate_yn(*ep2);
839 }
840 return tmp;
841}
842
843static struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
844{
845 struct expr *tmp = NULL;
846 expr_extract_eq(E_OR, &tmp, ep1, ep2);
847 if (tmp) {
848 *ep1 = expr_eliminate_yn(*ep1);
849 *ep2 = expr_eliminate_yn(*ep2);
850 }
851 return tmp;
852}
853
854static void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
855{
856#define e1 (*ep1)
857#define e2 (*ep2)
858 if (e1->type == type) {
859 expr_extract_eq(type, ep, &e1->left.expr, &e2);
860 expr_extract_eq(type, ep, &e1->right.expr, &e2);
861 return;
862 }
863 if (e2->type == type) {
864 expr_extract_eq(type, ep, ep1, &e2->left.expr);
865 expr_extract_eq(type, ep, ep1, &e2->right.expr);
866 return;
867 }
868 if (expr_eq(e1, e2)) {
869 *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
870 expr_free(e2);
871 if (type == E_AND) {
872 e1 = expr_alloc_symbol(&symbol_yes);
873 e2 = expr_alloc_symbol(&symbol_yes);
874 } else if (type == E_OR) {
875 e1 = expr_alloc_symbol(&symbol_no);
876 e2 = expr_alloc_symbol(&symbol_no);
877 }
878 }
879#undef e1
880#undef e2
881}
882
883struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) 772struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
884{ 773{
885 struct expr *e1, *e2; 774 struct expr *e1, *e2;