user_data: serious bug in handling modifications (missed errors)
[smatch.git] / smatch_param_filter.c
blob6e438cf04e6524f60c0a794cea79843fa2747982
1 /*
2 * sparse/smatch_param_filter.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * This is for functions like:
13 * void foo(int *x)
14 * {
15 * if (*x == 42)
16 * *x = 0;
17 * }
19 * The final value of *x depends on the input to the function but with *x == 42
20 * filtered out.
24 #include "smatch.h"
25 #include "smatch_extra.h"
26 #include "smatch_slist.h"
28 static int my_id;
30 STATE(modified);
31 STATE(original);
33 static struct state_list *start_states;
34 static struct state_list_stack *saved_stack;
35 static void save_start_states(struct statement *stmt)
37 start_states = get_all_states(SMATCH_EXTRA);
40 static void match_end_func(void)
42 free_slist(&start_states);
45 static void match_save_states(struct expression *expr)
47 push_slist(&saved_stack, start_states);
48 start_states = NULL;
51 static void match_restore_states(struct expression *expr)
53 start_states = pop_slist(&saved_stack);
56 static struct smatch_state *unmatched_state(struct sm_state *sm)
58 return &original;
61 static void extra_mod_hook(const char *name, struct symbol *sym, struct smatch_state *state)
63 int param;
65 param = get_param_num_from_sym(sym);
66 if (param < 0)
67 return;
69 set_state(my_id, name, sym, &modified);
72 static struct range_list *get_orig_rl(struct sm_state *sm)
74 struct range_list *ret = NULL;
75 struct sm_state *tmp;
76 struct smatch_state *extra;
78 FOR_EACH_PTR(sm->possible, tmp) {
79 if (tmp->state != &original)
80 continue;
81 extra = get_state_slist(tmp->pool, SMATCH_EXTRA, tmp->name, tmp->sym);
82 if (!extra) {
83 // sm_msg("debug: no value found in pool %p", tmp->pool);
84 return NULL;
86 ret = rl_union(ret, estate_rl(extra));
87 } END_FOR_EACH_PTR(tmp);
88 return ret;
91 static void print_one_mod_param(int return_id, char *return_ranges,
92 int param, struct sm_state *sm)
94 const char *param_name;
95 struct range_list *rl;
97 param_name = get_param_name(sm);
98 if (!param_name)
99 return;
100 rl = get_orig_rl(sm);
101 if (is_whole_rl(rl))
102 return;
104 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
105 param_name, show_rl(rl));
108 static void print_one_extra_param(int return_id, char *return_ranges,
109 int param, struct sm_state *sm)
111 struct smatch_state *old;
112 const char *param_name;
114 if (estate_is_whole(sm->state))
115 return;
116 old = get_state_slist(start_states, SMATCH_EXTRA, sm->name, sm->sym);
117 if (old && estates_equiv(old, sm->state))
118 return;
120 param_name = get_param_name(sm);
121 if (!param_name)
122 return;
124 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
125 param_name, sm->state->name);
128 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
130 struct state_list *extra_slist;
131 struct sm_state *tmp;
132 struct sm_state *sm;
133 int param;
135 extra_slist = get_all_states(SMATCH_EXTRA);
137 FOR_EACH_PTR(extra_slist, tmp) {
138 param = get_param_num_from_sym(tmp->sym);
139 if (param < 0)
140 continue;
142 * skip the parameter itself because that's handled by
143 * smatch_param_limit.c.
145 if (tmp->sym->ident && strcmp(tmp->sym->ident->name, tmp->name) == 0)
146 continue;
148 sm = get_sm_state(my_id, tmp->name, tmp->sym);
149 if (sm)
150 print_one_mod_param(return_id, return_ranges, param, sm);
151 else
152 print_one_extra_param(return_id, return_ranges, param, tmp);
153 } END_FOR_EACH_PTR(tmp);
155 free_slist(&extra_slist);
158 void register_param_filter(int id)
160 my_id = id;
162 add_hook(&save_start_states, AFTER_DEF_HOOK);
163 add_extra_mod_hook(&extra_mod_hook);
164 add_unmatched_state_hook(my_id, &unmatched_state);
165 add_split_return_callback(&print_return_value_param);
166 add_hook(&match_end_func, END_FUNC_HOOK);
167 add_hook(&match_save_states, INLINE_FN_START);
168 add_hook(&match_restore_states, INLINE_FN_END);