remove unused merge_pools() function.
[smatch.git] / smatch_function_hooks.c
blobf25519c127504aaa6f246281982c39f4edf8cbaa
1 #define _GNU_SOURCE
2 #include <search.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include "smatch.h"
6 #include "smatch_slist.h"
7 #include "smatch_extra.h"
9 ALLOCATOR(fcall_back, "call backs");
11 static struct hsearch_data func_hash;
13 #define REGULAR_CALL 0
14 #define CONDITIONAL_CALL 1
15 #define ASSIGN_CALL 2
16 #define RANGED_CALL 3
18 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
19 void *info)
21 struct fcall_back *cb;
23 cb = __alloc_fcall_back(0);
24 cb->type = type;
25 cb->call_back = call_back;
26 cb->info = info;
27 return cb;
30 static struct call_back_list *get_call_backs(const char *look_for)
32 ENTRY e, *ep;
34 e.key = (char *)look_for;
35 hsearch_r(e, FIND, &ep, &func_hash);
36 if (!ep)
37 return NULL;
38 return (struct call_back_list *)ep->data;
41 static void add_cb_hook(const char *look_for, struct fcall_back *cb)
43 ENTRY e, *ep;
44 char *old_key = NULL;
46 e.key = alloc_string(look_for);
47 hsearch_r(e, FIND, &ep, &func_hash);
48 if (!ep) {
49 struct call_back_list *list = NULL;
51 add_ptr_list(&list, cb);
52 e.data = list;
53 } else {
54 old_key = e.key;
55 e.key = ep->key;
56 add_ptr_list((struct call_back_list **)&ep->data, cb);
57 e.data = ep->data;
59 if (!hsearch_r(e, ENTER, &ep, &func_hash)) {
60 printf("Error hash table too small in smatch_function_hooks.c\n");
61 exit(1);
63 free_string(old_key);
66 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
68 struct fcall_back *cb;
70 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
71 add_cb_hook(look_for, cb);
74 void add_conditional_hook(const char *look_for, func_hook *call_back,
75 void *info)
77 struct fcall_back *cb;
79 cb = alloc_fcall_back(CONDITIONAL_CALL, call_back, info);
80 add_cb_hook(look_for, cb);
83 void add_function_assign_hook(const char *look_for, func_hook *call_back,
84 void *info)
86 struct fcall_back *cb;
88 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
89 add_cb_hook(look_for, cb);
92 void return_implies_state(const char *look_for, long long start, long long end,
93 func_hook *call_back, void *info)
95 struct fcall_back *cb;
97 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
98 cb->range = alloc_range_perm(start, end);
99 add_cb_hook(look_for, cb);
102 static void call_call_backs(struct call_back_list *list, int type,
103 const char *fn, struct expression *expr)
105 struct fcall_back *tmp;
107 FOR_EACH_PTR(list, tmp) {
108 if (tmp->type == type)
109 (tmp->call_back)(fn, expr, tmp->info);
110 } END_FOR_EACH_PTR(tmp);
113 static void match_function_call(struct expression *expr)
115 struct call_back_list *call_backs;
117 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
118 return;
119 call_backs = get_call_backs(expr->fn->symbol->ident->name);
120 if (!call_backs)
121 return;
122 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
123 expr);
126 static void assign_condition_funcs(const char *fn, struct expression *expr,
127 struct call_back_list *call_backs)
129 struct fcall_back *tmp;
130 struct sm_state *sm;
131 int conditional = 0;
132 char *var_name;
133 struct symbol *sym;
134 struct smatch_state *zero_state, *non_zero_state;
136 var_name = get_variable_from_expr(expr->left, &sym);
137 if (!var_name || !sym)
138 goto free;
140 __fake_conditions = 1;
141 FOR_EACH_PTR(call_backs, tmp) {
142 if (tmp->type != CONDITIONAL_CALL)
143 continue;
145 conditional = 1;
146 (tmp->call_back)(fn, expr->right, tmp->info);
147 } END_FOR_EACH_PTR(tmp);
148 if (conditional) {
149 zero_state = alloc_extra_state(0);
150 non_zero_state = add_filter(extra_undefined(), 0);
151 set_true_false_states(var_name, SMATCH_EXTRA, sym, non_zero_state, zero_state);
153 __fake_conditions = 0;
155 if (!conditional)
156 goto free;
158 merge_slist(&__fake_cond_true, __fake_cond_false);
160 FOR_EACH_PTR(__fake_cond_true, sm) {
161 __set_state(sm);
162 } END_FOR_EACH_PTR(sm);
163 free_slist(&__fake_cond_true);
164 free_slist(&__fake_cond_false);
165 free:
166 free_string(var_name);
169 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
170 struct data_range *drange)
172 struct call_back_list *ret = NULL;
173 struct fcall_back *tmp;
175 FOR_EACH_PTR(list, tmp) {
176 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
177 add_ptr_list(&ret, tmp);
178 } END_FOR_EACH_PTR(tmp);
179 return ret;
182 static void assign_ranged_funcs(const char *fn, struct expression *expr,
183 struct call_back_list *call_backs)
185 struct fcall_back *tmp;
186 struct sm_state *sm;
187 char *var_name;
188 struct symbol *sym;
189 struct smatch_state *extra_state;
190 struct state_list *final_states = NULL;
191 struct range_list *handled_ranges = NULL;
192 struct call_back_list *same_range_call_backs = NULL;
194 var_name = get_variable_from_expr(expr->left, &sym);
195 if (!var_name || !sym)
196 goto free;
198 __fake_cur = 1;
199 FOR_EACH_PTR(call_backs, tmp) {
200 if (tmp->type != RANGED_CALL)
201 continue;
202 if (in_list_exact(handled_ranges, tmp->range))
203 continue;
204 tack_on(&handled_ranges, tmp->range);
206 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
207 call_call_backs(same_range_call_backs, RANGED_CALL, fn, expr->right);
208 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
210 extra_state = alloc_extra_state_range(tmp->range->min, tmp->range->max);
211 set_state(var_name, SMATCH_EXTRA, sym, extra_state);
213 merge_slist(&final_states, __fake_cur_slist);
214 free_slist(&__fake_cur_slist);
215 } END_FOR_EACH_PTR(tmp);
216 __fake_cur = 0;
218 FOR_EACH_PTR(final_states, sm) {
219 __set_state(sm);
220 } END_FOR_EACH_PTR(sm);
222 free_slist(&final_states);
223 free:
224 free_string(var_name);
227 void function_comparison(int comparison, struct expression *expr, long long value, int left)
229 struct call_back_list *call_backs;
230 struct fcall_back *tmp;
231 const char *fn;
232 struct data_range *value_range;
233 struct state_list *true_states = NULL;
234 struct state_list *false_states = NULL;
235 struct sm_state *sm;
237 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
238 return;
239 fn = expr->fn->symbol->ident->name;
240 call_backs = get_call_backs(expr->fn->symbol->ident->name);
241 if (!call_backs)
242 return;
243 value_range = alloc_range(value, value);
245 __fake_cur = 1;
246 FOR_EACH_PTR(call_backs, tmp) {
247 if (tmp->type == RANGED_CALL &&
248 true_comparison_range_lr(comparison, tmp->range, value_range, left))
249 (tmp->call_back)(fn, expr, tmp->info);
250 merge_slist(&true_states, __fake_cur_slist);
251 free_slist(&__fake_cur_slist);
252 } END_FOR_EACH_PTR(tmp);
254 FOR_EACH_PTR(call_backs, tmp) {
255 if (tmp->type == RANGED_CALL &&
256 false_comparison_range_lr(comparison, tmp->range, value_range, left))
257 (tmp->call_back)(fn, expr, tmp->info);
258 merge_slist(&false_states, __fake_cur_slist);
259 free_slist(&__fake_cur_slist);
260 } END_FOR_EACH_PTR(tmp);
261 __fake_cur = 0;
263 FOR_EACH_PTR(true_states, sm) {
264 __set_true_false_sm(sm, NULL);
265 } END_FOR_EACH_PTR(sm);
266 FOR_EACH_PTR(false_states, sm) {
267 __set_true_false_sm(NULL, sm);
268 } END_FOR_EACH_PTR(sm);
270 if (true_states && !false_states)
271 smatch_msg("warning: unhandled false condition.");
272 if (!true_states && false_states)
273 smatch_msg("warning: unhandled true condition.");
274 free_slist(&true_states);
275 free_slist(&false_states);
278 void __match_initializer_call(struct symbol *sym)
280 struct call_back_list *call_backs;
281 struct expression *initializer = sym->initializer;
282 struct expression *e_assign, *e_symbol;
283 const char *fn;
285 if (initializer->fn->type != EXPR_SYMBOL
286 || !initializer->fn->symbol)
287 return;
288 fn = initializer->fn->symbol->ident->name;
289 call_backs = get_call_backs(fn);
290 if (!call_backs)
291 return;
293 e_assign = alloc_expression(initializer->pos, EXPR_ASSIGNMENT);
294 e_symbol = alloc_expression(initializer->pos, EXPR_SYMBOL);
295 e_symbol->symbol = sym;
296 e_symbol->symbol_name = sym->ident;
297 e_assign->left = e_symbol;
298 e_assign->right = initializer;
299 call_call_backs(call_backs, ASSIGN_CALL, fn, e_assign);
300 assign_condition_funcs(fn, e_assign, call_backs);
301 assign_ranged_funcs(fn, e_assign, call_backs);
304 static void match_assign_call(struct expression *expr)
306 struct call_back_list *call_backs;
307 const char *fn;
309 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
310 return;
311 fn = expr->right->fn->symbol->ident->name;
312 call_backs = get_call_backs(fn);
313 if (!call_backs)
314 return;
315 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
316 assign_condition_funcs(fn, expr, call_backs);
317 assign_ranged_funcs(fn, expr, call_backs);
320 static void match_conditional_call(struct expression *expr)
322 struct call_back_list *call_backs;
323 struct fcall_back *tmp;
324 struct sm_state *sm;
325 const char *fn;
327 if (expr->type != EXPR_CALL)
328 return;
330 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
331 return;
333 fn = expr->fn->symbol->ident->name;
334 call_backs = get_call_backs(fn);
335 if (!call_backs)
336 return;
337 __fake_conditions = 1;
338 FOR_EACH_PTR(call_backs, tmp) {
339 if (tmp->type != CONDITIONAL_CALL)
340 continue;
342 (tmp->call_back)(fn, expr, tmp->info);
344 FOR_EACH_PTR(__fake_cond_true, sm) {
345 __set_true_false_sm(sm, NULL);
346 } END_FOR_EACH_PTR(sm);
347 free_slist(&__fake_cond_true);
349 FOR_EACH_PTR(__fake_cond_false, sm) {
350 __set_true_false_sm(NULL, sm);
351 } END_FOR_EACH_PTR(sm);
352 free_slist(&__fake_cond_false);
354 } END_FOR_EACH_PTR(tmp);
355 __fake_conditions = 0;
358 void create_function_hash(void)
360 hcreate_r(10000, &func_hash); // Apparently 1000 is too few...
363 void register_function_hooks(int id)
365 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
366 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
367 add_hook(&match_conditional_call, CONDITION_HOOK);