math: Use function call information
[smatch.git] / smatch_param_filter.c
blob58d1845dffee02bafd1e2d5cf72616a529fe3746
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 const char *get_param_name(struct sm_state *sm)
74 char *param_name;
75 int name_len;
76 static char buf[256];
78 if (!sm->sym->ident)
79 return NULL;
81 param_name = sm->sym->ident->name;
82 name_len = strlen(param_name);
84 if (strcmp(sm->name, param_name) == 0) {
85 return "$$";
86 } else if (sm->name[name_len] == '-' && /* check for '-' from "->" */
87 strncmp(sm->name, param_name, name_len) == 0) {
88 snprintf(buf, sizeof(buf), "$$%s", sm->name + name_len);
89 return buf;
90 } else if (sm->name[0] == '*' && strcmp(sm->name + 1, param_name) == 0) {
91 return "*$$";
93 return NULL;
96 static char *get_orig_rl(struct sm_state *sm)
98 struct range_list *ret = NULL;
99 struct sm_state *tmp;
100 struct smatch_state *extra;
102 FOR_EACH_PTR(sm->possible, tmp) {
103 if (tmp->state != &original)
104 continue;
105 extra = get_state_slist(tmp->pool, SMATCH_EXTRA, tmp->name, tmp->sym);
106 if (!extra) {
107 // sm_msg("debug: no value found in pool %p", tmp->pool);
108 return NULL;
110 ret = rl_union(ret, estate_rl(extra));
111 } END_FOR_EACH_PTR(tmp);
112 return show_rl(ret);
115 static void print_one_mod_param(int return_id, char *return_ranges,
116 int param, struct sm_state *sm, struct state_list *slist)
118 const char *param_name;
119 char *filter;
121 param_name = get_param_name(sm);
122 if (!param_name)
123 return;
124 filter = get_orig_rl(sm);
125 if (!filter)
126 return;
128 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
129 param_name, filter);
132 static void print_one_extra_param(int return_id, char *return_ranges,
133 int param, struct sm_state *sm, struct state_list *slist)
135 struct smatch_state *old;
136 const char *param_name;
138 old = get_state_slist(start_states, SMATCH_EXTRA, sm->name, sm->sym);
139 if (old && estates_equiv(old, sm->state))
140 return;
142 param_name = get_param_name(sm);
143 if (!param_name)
144 return;
146 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
147 param_name, sm->state->name);
150 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist)
152 struct state_list *extra_slist;
153 struct sm_state *tmp;
154 struct sm_state *sm;
155 int param;
157 extra_slist = get_all_states_slist(SMATCH_EXTRA, slist);
159 FOR_EACH_PTR(extra_slist, tmp) {
160 param = get_param_num_from_sym(tmp->sym);
161 if (param < 0)
162 continue;
164 * skip the parameter itself because that's handled by
165 * smatch_param_limit.c.
167 if (tmp->sym->ident && strcmp(tmp->sym->ident->name, tmp->name) == 0)
168 continue;
170 sm = get_sm_state_slist(slist, my_id, tmp->name, tmp->sym);
171 if (sm)
172 print_one_mod_param(return_id, return_ranges, param, sm, slist);
173 else
174 print_one_extra_param(return_id, return_ranges, param, tmp, slist);
175 } END_FOR_EACH_PTR(tmp);
177 free_slist(&extra_slist);
180 void register_param_filter(int id)
182 my_id = id;
184 add_hook(&save_start_states, AFTER_DEF_HOOK);
185 add_extra_mod_hook(&extra_mod_hook);
186 add_unmatched_state_hook(my_id, &unmatched_state);
187 add_returned_state_callback(&print_return_value_param);
188 add_hook(&match_end_func, END_FUNC_HOOK);
189 add_hook(&match_save_states, INLINE_FN_START);
190 add_hook(&match_restore_states, INLINE_FN_END);