rosenberg: remove pahole dependency
[smatch.git] / smatch_param_filter.c
blob39a30ace1cce485f68e32c3a0d9691038f51b95d
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 struct range_list *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 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 struct range_list *rl;
121 param_name = get_param_name(sm);
122 if (!param_name)
123 return;
124 rl = get_orig_rl(sm);
125 if (is_whole_rl(rl))
126 return;
128 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
129 param_name, show_rl(rl));
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 if (estate_is_whole(sm->state))
139 return;
140 old = get_state_slist(start_states, SMATCH_EXTRA, sm->name, sm->sym);
141 if (old && estates_equiv(old, sm->state))
142 return;
144 param_name = get_param_name(sm);
145 if (!param_name)
146 return;
148 sql_insert_return_states(return_id, return_ranges, FILTER_VALUE, param,
149 param_name, sm->state->name);
152 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist)
154 struct state_list *extra_slist;
155 struct sm_state *tmp;
156 struct sm_state *sm;
157 int param;
159 extra_slist = get_all_states_slist(SMATCH_EXTRA, slist);
161 FOR_EACH_PTR(extra_slist, tmp) {
162 param = get_param_num_from_sym(tmp->sym);
163 if (param < 0)
164 continue;
166 * skip the parameter itself because that's handled by
167 * smatch_param_limit.c.
169 if (tmp->sym->ident && strcmp(tmp->sym->ident->name, tmp->name) == 0)
170 continue;
172 sm = get_sm_state_slist(slist, my_id, tmp->name, tmp->sym);
173 if (sm)
174 print_one_mod_param(return_id, return_ranges, param, sm, slist);
175 else
176 print_one_extra_param(return_id, return_ranges, param, tmp, slist);
177 } END_FOR_EACH_PTR(tmp);
179 free_slist(&extra_slist);
182 void register_param_filter(int id)
184 my_id = id;
186 add_hook(&save_start_states, AFTER_DEF_HOOK);
187 add_extra_mod_hook(&extra_mod_hook);
188 add_unmatched_state_hook(my_id, &unmatched_state);
189 add_returned_state_callback(&print_return_value_param);
190 add_hook(&match_end_func, END_FUNC_HOOK);
191 add_hook(&match_save_states, INLINE_FN_START);
192 add_hook(&match_restore_states, INLINE_FN_END);