From fc13c666b3a31d7e90d94b29c876ead3d992b3ad Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Apr 2017 15:57:03 +0300 Subject: [PATCH] states: fix handling switches inside conditions (fake_cur_stree) This is broken from when I re-worked how the fake_cur_stree worked. Before that we used to randomly merge the fake_cur_stree with the cur_stree. It had really complicated side effects but one side effect was that this stuff used to work. In the current code what was happening was that when we did a break we would discard everything from the fake_cur_stree. Now we create a new fake stream to store these states. We can't merge them in with the cur_stree because we're supposed to be able to discard all fake states. We also can't just mix the cur_stree in with the fake stree. The design of the fake stree is that we have to keep it separate. It's a little bit more complicated in some way, but more precise and transparent in other ways... Signed-off-by: Dan Carpenter --- smatch_states.c | 44 +++++++++++++++++++++++++++++++++++++++++++- validation/sm_switch3.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 validation/sm_switch3.c diff --git a/smatch_states.c b/smatch_states.c index f0c4c0a4..49844c96 100644 --- a/smatch_states.c +++ b/smatch_states.c @@ -56,6 +56,7 @@ static struct stree_stack *fake_cur_stree_stack; static int read_only; static struct stree_stack *break_stack; +static struct stree_stack *fake_break_stack; static struct stree_stack *switch_stack; static struct range_list_stack *remaining_cases; static struct stree_stack *default_stack; @@ -393,6 +394,7 @@ void __delete_all_states_sym(struct symbol *sym) delete_all_states_stree_stack_sym(&cond_false_stack, sym); delete_all_states_stree_stack_sym(&fake_cur_stree_stack, sym); delete_all_states_stree_stack_sym(&break_stack, sym); + delete_all_states_stree_stack_sym(&fake_break_stack, sym); delete_all_states_stree_stack_sym(&switch_stack, sym); delete_all_states_stree_stack_sym(&continue_stack, sym); @@ -578,6 +580,9 @@ void save_all_states(void) __add_ptr_list(&backup, break_stack, 0); break_stack = NULL; + __add_ptr_list(&backup, fake_break_stack, 0); + fake_break_stack = NULL; + __add_ptr_list(&backup, switch_stack, 0); switch_stack = NULL; __add_ptr_list(&backup, remaining_cases, 0); @@ -608,6 +613,7 @@ void restore_all_states(void) default_stack = pop_backup(); remaining_cases = pop_backup(); switch_stack = pop_backup(); + fake_break_stack = pop_backup(); break_stack = pop_backup(); fake_cur_stree_stack = pop_backup(); @@ -641,6 +647,7 @@ void clear_all_states(void) check_stree_stack_free(&cond_true_stack); check_stree_stack_free(&cond_false_stack); check_stree_stack_free(&break_stack); + check_stree_stack_free(&fake_break_stack); check_stree_stack_free(&switch_stack); check_stree_stack_free(&continue_stack); check_stree_stack_free(&fake_cur_stree_stack); @@ -931,6 +938,8 @@ void __merge_continues(void) void __push_breaks(void) { push_stree(&break_stack, NULL); + if (fake_cur_stree_stack) + push_stree(&fake_break_stack, NULL); } void __process_breaks(void) @@ -942,8 +951,17 @@ void __process_breaks(void) stree = clone_stree(cur_stree); else merge_stree(&stree, cur_stree); - push_stree(&break_stack, stree); + + if (!fake_cur_stree_stack) + return; + + stree = pop_stree(&fake_break_stack); + if (!stree) + stree = clone_stree(top_stree(fake_cur_stree_stack)); + else + merge_stree(&stree, top_stree(fake_cur_stree_stack)); + push_stree(&fake_break_stack, stree); } int __has_breaks(void) @@ -960,16 +978,40 @@ int __has_breaks(void) void __merge_breaks(void) { struct stree *stree; + struct sm_state *sm; stree = pop_stree(&break_stack); merge_stree(&cur_stree, stree); free_stree(&stree); + + if (!fake_cur_stree_stack) + return; + + stree = pop_stree(&fake_break_stack); + update_stree_with_merged(&stree); + FOR_EACH_SM(stree, sm) { + overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); + } END_FOR_EACH_SM(sm); + free_stree(&stree); } void __use_breaks(void) { + struct stree *stree; + struct sm_state *sm; + free_stree(&cur_stree); cur_stree = pop_stree(&break_stack); + + if (!fake_cur_stree_stack) + return; + stree = pop_stree(&fake_break_stack); + FOR_EACH_SM(stree, sm) { + overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); + } END_FOR_EACH_SM(sm); + free_stree(&stree); + + } void __save_switch_states(struct expression *switch_expr) diff --git a/validation/sm_switch3.c b/validation/sm_switch3.c new file mode 100644 index 00000000..0478ef0b --- /dev/null +++ b/validation/sm_switch3.c @@ -0,0 +1,49 @@ +#include "check_debug.h" + +int a, b; + +int frob(void); + +int test(int size) +{ + a = 0; + + if (({switch (frob()) { + case 1: + a = 2; + break; + default: + a = 3; + } + b;})) + ; + __smatch_implied(a); + + a = 4; + + if (({switch (2) { + case 1: + a = 5; + break; + case 2: + a = 6; + break; + default: + a = 7; + } + b;})) + ; + __smatch_implied(a); + + return 0; +} + +/* + * check-name: smatch: switch #3 + * check-command: smatch -I.. sm_switch3.c + * + * check-output-start +sm_switch3.c:20 test() implied: a = '2-3' +sm_switch3.c:36 test() implied: a = '6' + * check-output-end + */ -- 2.11.4.GIT