From f8c2700e836b677fb50d09efd9612624bef7c43d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Feb 2009 16:54:23 +0300 Subject: [PATCH] Try again removing states from pools. There was a patch that just deleted a state from the pool but I had to revert it because on some paths a state is part of the pool and some it's not. The new code looks in cur_slist to see what pools a state is in using is_currently_in_pool(). That was confusing as pants... :/ Signed-off-by: Dan Carpenter --- smatch.h | 1 + smatch_implied.c | 45 ++++++++++---------------------------------- smatch_slist.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- smatch_slist.h | 5 ++++- smatch_states.c | 5 +++++ 5 files changed, 75 insertions(+), 38 deletions(-) diff --git a/smatch.h b/smatch.h index dc5a7a04..9ac800f2 100644 --- a/smatch.h +++ b/smatch.h @@ -135,6 +135,7 @@ int known_condition_true(struct expression *expr); /* smatch_states.c */ extern int debug_states; +struct state_list *__get_cur_slist(); void nullify_path(); void __unnullify_path(); int __path_is_null(); diff --git a/smatch_implied.c b/smatch_implied.c index f56242d7..9b3c54d2 100644 --- a/smatch_implied.c +++ b/smatch_implied.c @@ -48,41 +48,15 @@ #include "smatch.h" #include "smatch_slist.h" -/* - * This function gets all the states which are implied by a non zero value. - * So for example for the code: - * if (c) { - * We would want to know what was implied by c is non zero. - */ - -static struct state_list *get_non_zero_filtered(struct sm_state *sm_state) -{ - struct state_list *list; - struct smatch_state *s; - struct state_list *ret = NULL; - - FOR_EACH_PTR(sm_state->pools, list) { - s = get_state_slist(list, sm_state->name, sm_state->owner, - sm_state->sym); - if (s == &undefined) { - del_slist(&ret); - return NULL; - } - if (s->data && *(int *)s->data != 0) { - if (!ret) - ret = clone_slist(list); - else - filter(&ret, list); - } - } END_FOR_EACH_PTR(list); - return ret; -} +#define EQUALS 0 +#define NOTEQUALS 1 /* * What are the implications if (foo == num) ... */ -static struct state_list *get_equals_filtered(struct sm_state *sm_state, int num) +static struct state_list *get_eq_neq_filtered(struct sm_state *sm_state, + int eq_neq, int num) { struct state_list *list; struct smatch_state *s; @@ -95,11 +69,12 @@ static struct state_list *get_equals_filtered(struct sm_state *sm_state, int num del_slist(&ret); return NULL; } - if (s->data && *(int *)s->data == num) { + if (s->data && ((eq_neq == EQUALS && *(int *)s->data == num) || + (eq_neq == NOTEQUALS && *(int *)s->data != num))) { if (!ret) - ret = clone_slist(list); + ret = clone_states_in_pool(list, __get_cur_slist()); else - filter(&ret, list); + filter(&ret, list, __get_cur_slist()); } } END_FOR_EACH_PTR(list); return ret; @@ -127,8 +102,8 @@ void __implied_states_hook(struct expression *expr) return; if (!state->pools) return; - implied_true = get_non_zero_filtered(state); - implied_false = get_equals_filtered(state, 0); + implied_true = get_eq_neq_filtered(state, NOTEQUALS, 0); + implied_false = get_eq_neq_filtered(state, EQUALS, 0); if (debug_states) { printf("Setting the following implied states for the true path.\n"); __print_slist(implied_true); diff --git a/smatch_slist.c b/smatch_slist.c index 7656672e..0b5568ab 100644 --- a/smatch_slist.c +++ b/smatch_slist.c @@ -478,6 +478,56 @@ void merge_slist(struct state_list **to, struct state_list *slist) } /* + * is_currently_in_pool() is used because we remove states from pools. + * When set_state() is called then we set ->pools to NULL, but on + * other paths the state is still a member of those pools. + * Confusing huh? + * if (foo) { + * bar = 1; + * a = malloc(); + * } + * if (!a) + * return; + * if (bar) + * a->b = x; + */ +static int is_currently_in_pool(struct sm_state *sm, struct state_list *pool, + struct state_list *cur_slist) +{ + struct sm_state *cur_state; + struct state_list *tmp; + + cur_state = get_sm_state_slist(cur_slist, sm->name, sm->owner, sm->sym); + if (!cur_state) + return 0; + + FOR_EACH_PTR(cur_state->pools, tmp) { + if (tmp == pool) + return 1; + } END_FOR_EACH_PTR(tmp); + return 0; +} + +struct state_list *clone_states_in_pool(struct state_list *pool, + struct state_list *cur_slist) +{ + struct sm_state *state; + struct sm_state *tmp; + struct state_list *to_slist = NULL; + + FOR_EACH_PTR(pool, state) { + if (is_currently_in_pool(state, pool, cur_slist)) { + tmp = clone_state(state); + add_ptr_list(&to_slist, tmp); + } + } END_FOR_EACH_PTR(state); +#ifdef CHECKORDER + check_order(to_slist); +#endif + return to_slist; +} + +/* * filter() is used to find what states are the same across * a series of slists. * It takes a **slist and a *filter. @@ -485,7 +535,8 @@ void merge_slist(struct state_list **to, struct state_list *slist) * The reason you would want to do this is if you want to * know what other states are true if one state is true. (smatch_implied). */ -void filter(struct state_list **slist, struct state_list *filter) +void filter(struct state_list **slist, struct state_list *filter, + struct state_list *cur_slist) { struct sm_state *s_one, *s_two; struct state_list *results = NULL; @@ -505,8 +556,10 @@ void filter(struct state_list **slist, struct state_list *filter) } else if (cmp_sm_states(s_one, s_two) == 0) { /* todo. pointer comparison works fine for most things except smatch_extra. we may need a hook here. */ - if (s_one->state == s_two->state) + if (s_one->state == s_two->state && + is_currently_in_pool(s_two, filter, cur_slist)) { add_ptr_list(&results, s_one); + } NEXT_PTR_LIST(s_one); NEXT_PTR_LIST(s_two); } else { diff --git a/smatch_slist.h b/smatch_slist.h index 095ec452..995d718f 100644 --- a/smatch_slist.h +++ b/smatch_slist.h @@ -74,7 +74,10 @@ struct smatch_state *get_state_stack(struct state_list_stack *stack, const char int owner, struct symbol *sym); void merge_slist(struct state_list **to, struct state_list *slist); -void filter(struct state_list **slist, struct state_list *filter); +struct state_list *clone_states_in_pool(struct state_list *pool, + struct state_list *cur_slist); +void filter(struct state_list **slist, struct state_list *filter, + struct state_list *cur_slist); void and_slist_stack(struct state_list_stack **slist_stack); void or_slist_stack(struct state_list_stack **slist_stack); diff --git a/smatch_states.c b/smatch_states.c index e2521819..587f8582 100644 --- a/smatch_states.c +++ b/smatch_states.c @@ -126,6 +126,11 @@ struct state_list *get_all_states(int owner) return slist; } +struct state_list *__get_cur_slist() +{ + return cur_slist; +} + void set_true_false_states(const char *name, int owner, struct symbol *sym, struct smatch_state *true_state, struct smatch_state *false_state) -- 2.11.4.GIT