smatch_comparison: store how two variables compare with each other
[smatch.git] / smatch_function_hooks.c
blob09797049952e6feb7259916aee193fab11ddc2d3
1 /*
2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are several types of function hooks:
12 * add_function_hook() - For any time a function is called.
13 * add_function_assign_hook() - foo = the_function().
14 * add_implied_return_hook() - Calculates the implied return value.
15 * add_macro_assign_hook() - foo = the_macro().
16 * return_implies_state() - For when a return value of 1 implies locked
17 * and 0 implies unlocked. etc. etc.
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
28 struct fcall_back {
29 int type;
30 struct data_range *range;
31 union {
32 func_hook *call_back;
33 implication_hook *ranged;
34 implied_return_hook *implied_return;
35 } u;
36 void *info;
39 ALLOCATOR(fcall_back, "call backs");
40 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
42 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
43 static struct hashtable *func_hash;
45 #define REGULAR_CALL 0
46 #define RANGED_CALL 1
47 #define ASSIGN_CALL 2
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback {
53 int type;
54 return_implies_hook *callback;
56 ALLOCATOR(return_implies_callback, "return_implies callbacks");
57 DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback);
58 static struct db_implies_list *db_return_states_list;
60 typedef void (void_fn)(void);
61 DECLARE_PTR_LIST(void_fn_list, void_fn *);
62 static struct void_fn_list *return_states_before;
63 static struct void_fn_list *return_states_after;
65 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
66 void *info)
68 struct fcall_back *cb;
70 cb = __alloc_fcall_back(0);
71 cb->type = type;
72 cb->u.call_back = call_back;
73 cb->info = info;
74 return cb;
77 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
79 struct fcall_back *cb;
81 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
82 add_callback(func_hash, look_for, cb);
85 void add_function_assign_hook(const char *look_for, func_hook *call_back,
86 void *info)
88 struct fcall_back *cb;
90 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
91 add_callback(func_hash, look_for, cb);
94 void add_implied_return_hook(const char *look_for,
95 implied_return_hook *call_back,
96 void *info)
98 struct fcall_back *cb;
100 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
101 add_callback(func_hash, look_for, cb);
104 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
105 void *info)
107 struct fcall_back *cb;
109 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
110 add_callback(func_hash, look_for, cb);
113 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
114 void *info)
116 struct fcall_back *cb;
118 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
119 add_callback(func_hash, look_for, cb);
122 void return_implies_state(const char *look_for, long long start, long long end,
123 implication_hook *call_back, void *info)
125 struct fcall_back *cb;
127 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
128 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
129 add_callback(func_hash, look_for, cb);
132 void add_db_return_states_callback(int type, return_implies_hook *callback)
134 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
136 cb->type = type;
137 cb->callback = callback;
138 add_ptr_list(&db_return_states_list, cb);
141 void add_db_return_states_before(void_fn *fn)
143 void_fn **p = malloc(sizeof(void_fn *));
144 *p = fn;
145 add_ptr_list(&return_states_before, p);
148 void add_db_return_states_after(void_fn *fn)
150 void_fn **p = malloc(sizeof(void_fn *));
151 *p = fn;
152 add_ptr_list(&return_states_after, p);
155 static void call_return_states_before_hooks(void)
157 void_fn **fn;
159 FOR_EACH_PTR(return_states_before, fn) {
160 (*fn)();
161 } END_FOR_EACH_PTR(fn);
164 static void call_return_states_after_hooks(void)
166 void_fn **fn;
168 FOR_EACH_PTR(return_states_after, fn) {
169 (*fn)();
170 } END_FOR_EACH_PTR(fn);
173 static int call_call_backs(struct call_back_list *list, int type,
174 const char *fn, struct expression *expr)
176 struct fcall_back *tmp;
177 int handled = 0;
179 FOR_EACH_PTR(list, tmp) {
180 if (tmp->type == type) {
181 (tmp->u.call_back)(fn, expr, tmp->info);
182 handled = 1;
184 } END_FOR_EACH_PTR(tmp);
186 return handled;
189 static void call_ranged_call_backs(struct call_back_list *list,
190 const char *fn, struct expression *call_expr,
191 struct expression *assign_expr)
193 struct fcall_back *tmp;
195 FOR_EACH_PTR(list, tmp) {
196 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
197 } END_FOR_EACH_PTR(tmp);
200 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
201 struct data_range *drange)
203 struct call_back_list *ret = NULL;
204 struct fcall_back *tmp;
206 FOR_EACH_PTR(list, tmp) {
207 if (tmp->type != RANGED_CALL)
208 continue;
209 if (ranges_equiv(tmp->range, drange))
210 add_ptr_list(&ret, tmp);
211 } END_FOR_EACH_PTR(tmp);
212 return ret;
215 static int in_list_exact_sval(struct range_list *list, struct data_range *drange)
217 struct data_range *tmp;
219 FOR_EACH_PTR(list, tmp) {
220 if (ranges_equiv(tmp, drange))
221 return 1;
222 } END_FOR_EACH_PTR(tmp);
223 return 0;
226 static int assign_ranged_funcs(const char *fn, struct expression *expr,
227 struct call_back_list *call_backs)
229 struct fcall_back *tmp;
230 struct sm_state *sm;
231 char *var_name;
232 struct symbol *sym;
233 struct smatch_state *estate;
234 struct state_list *tmp_slist;
235 struct state_list *final_states = NULL;
236 struct range_list *handled_ranges = NULL;
237 struct call_back_list *same_range_call_backs = NULL;
238 int handled = 0;
240 if (!call_backs)
241 return 0;
243 var_name = expr_to_str_sym(expr->left, &sym);
244 if (!var_name || !sym)
245 goto free;
247 FOR_EACH_PTR(call_backs, tmp) {
248 if (tmp->type != RANGED_CALL)
249 continue;
251 if (in_list_exact_sval(handled_ranges, tmp->range))
252 continue;
253 __push_fake_cur_slist();
254 tack_on(&handled_ranges, tmp->range);
256 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
257 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
258 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
260 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
261 set_extra_mod(var_name, sym, estate);
263 tmp_slist = __pop_fake_cur_slist();
264 merge_slist(&final_states, tmp_slist);
265 free_slist(&tmp_slist);
266 handled = 1;
267 } END_FOR_EACH_PTR(tmp);
269 FOR_EACH_PTR(final_states, sm) {
270 __set_sm(sm);
271 } END_FOR_EACH_PTR(sm);
273 free_slist(&final_states);
274 free:
275 free_string(var_name);
276 return handled;
279 static int call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
281 struct call_back_list *call_backs;
282 struct fcall_back *tmp;
283 const char *fn;
284 struct data_range *value_range;
285 struct state_list *true_states = NULL;
286 struct state_list *false_states = NULL;
287 struct state_list *tmp_slist;
288 struct sm_state *sm;
290 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
291 return 0;
292 fn = expr->fn->symbol->ident->name;
293 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
294 if (!call_backs)
295 return 0;
296 value_range = alloc_range(sval, sval);
298 /* set true states */
299 __push_fake_cur_slist();
300 FOR_EACH_PTR(call_backs, tmp) {
301 if (tmp->type != RANGED_CALL)
302 continue;
303 if (!true_comparison_range_LR(comparison, tmp->range, value_range, left))
304 continue;
305 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
306 } END_FOR_EACH_PTR(tmp);
307 tmp_slist = __pop_fake_cur_slist();
308 merge_slist(&true_states, tmp_slist);
309 free_slist(&tmp_slist);
311 /* set false states */
312 __push_fake_cur_slist();
313 FOR_EACH_PTR(call_backs, tmp) {
314 if (tmp->type != RANGED_CALL)
315 continue;
316 if (!false_comparison_range_LR(comparison, tmp->range, value_range, left))
317 continue;
318 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
319 } END_FOR_EACH_PTR(tmp);
320 tmp_slist = __pop_fake_cur_slist();
321 merge_slist(&false_states, tmp_slist);
322 free_slist(&tmp_slist);
324 FOR_EACH_PTR(true_states, sm) {
325 __set_true_false_sm(sm, NULL);
326 } END_FOR_EACH_PTR(sm);
327 FOR_EACH_PTR(false_states, sm) {
328 __set_true_false_sm(NULL, sm);
329 } END_FOR_EACH_PTR(sm);
331 free_slist(&true_states);
332 free_slist(&false_states);
333 return 1;
336 struct db_callback_info {
337 int true_side;
338 int comparison;
339 struct expression *expr;
340 struct range_list *rl;
341 int left;
342 struct state_list *slist;
343 struct db_implies_list *callbacks;
345 static struct db_callback_info db_info;
346 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
348 struct range_list *ret_range;
349 int type, param;
350 char *key, *value;
351 struct return_implies_callback *tmp;
353 if (argc != 5)
354 return 0;
356 str_to_rl(get_type(db_info.expr), argv[0], &ret_range);
357 type = atoi(argv[1]);
358 param = atoi(argv[2]);
359 key = argv[3];
360 value = argv[4];
362 if (db_info.true_side) {
363 if (!possibly_true_rl_LR(db_info.comparison,
364 ret_range, db_info.rl,
365 db_info.left))
366 return 0;
367 } else {
368 if (!possibly_false_rl_LR(db_info.comparison,
369 ret_range, db_info.rl,
370 db_info.left))
371 return 0;
374 FOR_EACH_PTR(db_info.callbacks, tmp) {
375 if (tmp->type == type)
376 tmp->callback(db_info.expr, param, key, value);
377 } END_FOR_EACH_PTR(tmp);
378 return 0;
381 void compare_db_return_states_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
383 struct symbol *sym;
384 static char sql_filter[1024];
385 struct state_list *true_states;
386 struct state_list *false_states;
387 struct sm_state *sm;
389 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
390 return;
392 sym = expr->fn->symbol;
393 if (!sym)
394 return;
396 if (sym->ctype.modifiers & MOD_STATIC) {
397 snprintf(sql_filter, 1024,
398 "file = '%s' and function = '%s' and static = '1';",
399 get_filename(), sym->ident->name);
400 } else {
401 snprintf(sql_filter, 1024,
402 "function = '%s' and static = '0';", sym->ident->name);
405 db_info.comparison = comparison;
406 db_info.expr = expr;
407 db_info.rl = alloc_rl(sval, sval);
408 db_info.left = left;
409 db_info.callbacks = db_return_states_list;
411 call_return_states_before_hooks();
413 db_info.true_side = 1;
414 __push_fake_cur_slist();
415 run_sql(db_compare_callback,
416 "select return, type, parameter, key, value from return_states where %s",
417 sql_filter);
418 true_states = __pop_fake_cur_slist();
420 db_info.true_side = 0;
421 __push_fake_cur_slist();
422 run_sql(db_compare_callback,
423 "select return, type, parameter, key, value from return_states where %s",
424 sql_filter);
425 false_states = __pop_fake_cur_slist();
427 FOR_EACH_PTR(true_states, sm) {
428 __set_true_false_sm(sm, NULL);
429 } END_FOR_EACH_PTR(sm);
430 FOR_EACH_PTR(false_states, sm) {
431 __set_true_false_sm(NULL, sm);
432 } END_FOR_EACH_PTR(sm);
434 call_return_states_after_hooks();
436 free_slist(&true_states);
437 free_slist(&false_states);
442 void function_comparison(int comparison, struct expression *expr, sval_t sval, int left)
444 if (call_implies_callbacks(comparison, expr, sval, left))
445 return;
446 compare_db_return_states_callbacks(comparison, expr, sval, left);
449 static int prev_return_id;
450 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
452 struct range_list *ret_range;
453 int type, param;
454 char *key, *value;
455 struct return_implies_callback *tmp;
456 struct state_list *slist;
457 int return_id;
459 if (argc != 6)
460 return 0;
462 return_id = atoi(argv[0]);
463 str_to_rl(get_type(db_info.expr->right), argv[1], &ret_range);
464 if (!ret_range)
465 ret_range = alloc_whole_rl(cur_func_return_type());
466 type = atoi(argv[2]);
467 param = atoi(argv[3]);
468 key = argv[4];
469 value = argv[5];
471 if (prev_return_id != -1 && return_id != prev_return_id) {
472 slist = __pop_fake_cur_slist();
473 merge_slist(&db_info.slist, slist);
474 __push_fake_cur_slist();
476 prev_return_id = return_id;
478 FOR_EACH_PTR(db_return_states_list, tmp) {
479 if (tmp->type == type)
480 tmp->callback(db_info.expr, param, key, value);
481 } END_FOR_EACH_PTR(tmp);
482 ret_range = cast_rl(get_type(db_info.expr->left), ret_range);
483 set_extra_expr_mod(db_info.expr->left, alloc_estate_rl(ret_range));
485 return 0;
488 static int db_return_states_assign(struct expression *expr)
490 struct expression *right;
491 struct symbol *sym;
492 struct sm_state *sm;
493 struct state_list *slist;
494 static char sql_filter[1024];
495 int handled = 0;
497 right = strip_expr(expr->right);
498 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
499 return 0;
501 sym = right->fn->symbol;
502 if (!sym)
503 return 0;
505 if (sym->ctype.modifiers & MOD_STATIC) {
506 snprintf(sql_filter, 1024,
507 "file = '%s' and function = '%s' and static = '1';",
508 get_filename(), sym->ident->name);
509 } else {
510 snprintf(sql_filter, 1024,
511 "function = '%s' and static = '0';", sym->ident->name);
514 prev_return_id = -1;
515 db_info.expr = expr;
516 db_info.slist = NULL;
518 call_return_states_before_hooks();
520 __push_fake_cur_slist();
521 run_sql(db_assign_return_states_callback,
522 "select return_id, return, type, parameter, key, value from return_states where %s",
523 sql_filter);
524 slist = __pop_fake_cur_slist();
525 merge_slist(&db_info.slist, slist);
527 FOR_EACH_PTR(db_info.slist, sm) {
528 __set_sm(sm);
529 handled = 1;
530 } END_FOR_EACH_PTR(sm);
532 call_return_states_after_hooks();
534 return handled;
537 static int handle_implied_return(struct expression *expr)
539 struct range_list *rl;
541 if (!get_implied_return(expr->right, &rl))
542 return 0;
543 rl = cast_rl(get_type(expr->left), rl);
544 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
545 return 1;
548 static void match_assign_call(struct expression *expr)
550 struct call_back_list *call_backs;
551 const char *fn;
552 struct expression *right;
553 int handled = 0;
555 right = strip_expr(expr->right);
556 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
557 set_extra_expr_mod(expr->left, alloc_estate_whole(get_type(expr->left)));
558 return;
560 fn = right->fn->symbol->ident->name;
563 * some of these conflict (they try to set smatch extra twice), so we
564 * call them in order from least important to most important.
567 call_backs = search_callback(func_hash, (char *)fn);
568 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
570 handled |= db_return_states_assign(expr);
571 handled |= assign_ranged_funcs(fn, expr, call_backs);
572 handled |= handle_implied_return(expr);
574 if (!handled) {
575 struct range_list *rl;
577 if (!get_implied_rl(expr->right, &rl))
578 rl = alloc_whole_rl(get_type(expr->right));
579 rl = cast_rl(get_type(expr->left), rl);
580 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
584 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
586 struct range_list *ret_range;
587 int type, param;
588 char *key, *value;
589 struct return_implies_callback *tmp;
590 struct state_list *slist;
591 int return_id;
593 if (argc != 6)
594 return 0;
596 return_id = atoi(argv[0]);
597 str_to_rl(get_type(db_info.expr), argv[1], &ret_range);
598 type = atoi(argv[2]);
599 param = atoi(argv[3]);
600 key = argv[4];
601 value = argv[5];
603 if (prev_return_id != -1 && return_id != prev_return_id) {
604 slist = __pop_fake_cur_slist();
605 merge_slist(&db_info.slist, slist);
606 __push_fake_cur_slist();
607 __unnullify_path();
609 prev_return_id = return_id;
611 FOR_EACH_PTR(db_return_states_list, tmp) {
612 if (tmp->type == type)
613 tmp->callback(db_info.expr, param, key, value);
614 } END_FOR_EACH_PTR(tmp);
616 return 0;
619 static void db_return_states(struct expression *expr)
621 struct symbol *sym;
622 struct sm_state *sm;
623 struct state_list *slist;
624 static char sql_filter[1024];
626 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
627 return;
629 sym = expr->fn->symbol;
630 if (!sym)
631 return;
633 if (sym->ctype.modifiers & MOD_STATIC) {
634 snprintf(sql_filter, 1024,
635 "file = '%s' and function = '%s' and static = '1';",
636 get_filename(), sym->ident->name);
637 } else {
638 snprintf(sql_filter, 1024,
639 "function = '%s' and static = '0';", sym->ident->name);
642 prev_return_id = -1;
643 db_info.expr = expr;
644 db_info.slist = NULL;
646 call_return_states_before_hooks();
648 __push_fake_cur_slist();
649 __unnullify_path();
650 run_sql(db_return_states_callback,
651 "select return_id, return, type, parameter, key, value from return_states where %s",
652 sql_filter);
653 slist = __pop_fake_cur_slist();
654 merge_slist(&db_info.slist, slist);
656 FOR_EACH_PTR(db_info.slist, sm) {
657 __set_sm(sm);
658 } END_FOR_EACH_PTR(sm);
660 call_return_states_after_hooks();
663 static int is_assigned_call(struct expression *expr)
665 struct expression *tmp;
667 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
668 if (tmp->type == EXPR_ASSIGNMENT && strip_expr(tmp->right) == expr)
669 return 1;
670 if (tmp->pos.line < expr->pos.line)
671 return 0;
672 } END_FOR_EACH_PTR_REVERSE(tmp);
673 return 0;
676 static void db_return_states_call(struct expression *expr)
678 if (is_assigned_call(expr))
679 return;
680 db_return_states(expr);
683 static void match_function_call(struct expression *expr)
685 struct call_back_list *call_backs;
687 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
688 return;
689 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
690 if (call_backs)
691 call_call_backs(call_backs, REGULAR_CALL,
692 expr->fn->symbol->ident->name, expr);
693 db_return_states_call(expr);
696 static void match_macro_assign(struct expression *expr)
698 struct call_back_list *call_backs;
699 const char *macro;
700 struct expression *right;
702 right = strip_expr(expr->right);
703 macro = get_macro_name(right->pos);
704 call_backs = search_callback(func_hash, (char *)macro);
705 if (!call_backs)
706 return;
707 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
708 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
711 int get_implied_return(struct expression *expr, struct range_list **rl)
713 struct call_back_list *call_backs;
714 struct fcall_back *tmp;
715 int handled = 0;
716 char *fn;
718 *rl = NULL;
720 expr = strip_expr(expr);
721 fn = expr_to_str(expr->fn);
722 if (!fn)
723 goto out;
725 call_backs = search_callback(func_hash, fn);
727 FOR_EACH_PTR(call_backs, tmp) {
728 if (tmp->type == IMPLIED_RETURN) {
729 (tmp->u.implied_return)(expr, tmp->info, rl);
730 handled = 1;
732 } END_FOR_EACH_PTR(tmp);
734 out:
735 free_string(fn);
736 return handled;
739 void create_function_hook_hash(void)
741 func_hash = create_function_hashtable(5000);
744 void register_function_hooks(int id)
746 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
747 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
748 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);