flow: strip out parentheses before faking a return
[smatch.git] / smatch_function_hooks.c
blobc00ae3f17bd536b48cb57fa0edab2aa43353f281
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * There are several types of function hooks.
21 * The param_key hooks are probably the right things to use going forward.
22 * They give you a name/sym pair so it means less code in the checks.
24 * The add_function_hook() functions are trigger for every call. The
25 * "return_implies" are triggered for specific return ranges. The "exact"
26 * variants will be triggered if it's *definitely* in the range where the
27 * others will be triggered if it's *possibly* in the range. The "late"
28 * variants will be triggered after the others have run.
30 * There are a few miscellaneous things like add_function_assign_hook() and
31 * add_macro_assign_hook() which are only triggered for assignments. The
32 * add_implied_return_hook() let's you manually adjust the return range.
34 * Every call:
35 * add_function_param_key_hook()
36 * add_function_param_key_hook_late()
37 * add_function_hook()
39 * Just for some return ranges:
40 * return_implies_param_key()
41 * return_implies_param_key_exact()
42 * return_implies_state()
43 * select_return_param_key() (It's weird that this is not in smatch_db.c)
45 * For Assignments:
46 * add_function_assign_hook()
48 * For Macro Assignments:
49 * add_macro_assign_hook()
51 * Manipulate the return range.
52 * add_implied_return_hook()
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <ctype.h>
58 #include "smatch.h"
59 #include "smatch_slist.h"
60 #include "smatch_extra.h"
61 #include "smatch_function_hashtable.h"
62 #include "smatch_expression_stacks.h"
64 struct fcall_back {
65 int type;
66 struct data_range *range;
67 union {
68 func_hook *call_back;
69 implication_hook *ranged;
70 implied_return_hook *implied_return;
71 } u;
72 void *info;
75 ALLOCATOR(fcall_back, "call backs");
76 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
78 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
79 static struct hashtable *func_hash;
81 int __in_fake_parameter_assign;
83 enum fn_hook_type {
84 REGULAR_CALL,
85 REGULAR_CALL_LATE,
86 RANGED_CALL,
87 RANGED_EXACT,
88 ASSIGN_CALL,
89 IMPLIED_RETURN,
90 MACRO_ASSIGN,
91 MACRO_ASSIGN_EXTRA,
94 struct param_key_data {
95 param_key_hook *call_back;
96 int param;
97 const char *key;
98 void *info;
101 struct return_implies_callback {
102 int type;
103 bool param_key;
104 union {
105 return_implies_hook *callback;
106 param_key_hook *pk_callback;
109 ALLOCATOR(return_implies_callback, "return_implies callbacks");
110 DECLARE_PTR_LIST(db_implies_list, struct return_implies_callback);
111 static struct db_implies_list *db_return_states_list;
113 static struct void_fn_list *return_states_before;
114 static struct void_fn_list *return_states_after;
115 static struct string_hook_list *return_string_hooks;
117 struct db_callback_info {
118 int true_side;
119 int comparison;
120 struct expression *expr;
121 struct range_list *rl;
122 int left;
123 struct stree *stree;
124 struct stree *implied;
125 struct db_implies_list *callbacks;
126 struct db_implies_list *called;
127 int prev_return_id;
128 int cull;
129 int has_states;
130 char *ret_str;
131 struct smatch_state *ret_state;
132 struct expression *var_expr;
133 struct expression_list *fake_param_assign_stack;
134 int handled;
137 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
138 void *info)
140 struct fcall_back *cb;
142 cb = __alloc_fcall_back(0);
143 cb->type = type;
144 cb->u.call_back = call_back;
145 cb->info = info;
146 return cb;
149 static const char *get_fn_name(struct expression *fn)
151 fn = strip_expr(fn);
152 if (!fn)
153 return NULL;
154 if (fn->type == EXPR_SYMBOL && fn->symbol)
155 return fn->symbol->ident->name;
156 return get_member_name(fn);
159 static struct call_back_list *get_call_backs(const char *fn_name)
161 if (!fn_name)
162 return NULL;
163 return search_callback(func_hash, (char *)fn_name);
166 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
168 struct fcall_back *cb;
170 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
171 add_callback(func_hash, look_for, cb);
174 void add_function_hook_late(const char *look_for, func_hook *call_back, void *info)
176 struct fcall_back *cb;
178 cb = alloc_fcall_back(REGULAR_CALL_LATE, call_back, info);
179 add_callback(func_hash, look_for, cb);
182 void add_function_assign_hook(const char *look_for, func_hook *call_back,
183 void *info)
185 struct fcall_back *cb;
187 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
188 add_callback(func_hash, look_for, cb);
191 static void register_funcs_from_file_helper(const char *file,
192 func_hook *call_back, void *info,
193 bool assign)
195 struct token *token;
196 const char *func;
197 char name[64];
199 snprintf(name, sizeof(name), "%s.%s", option_project_str, file);
200 token = get_tokens_file(name);
201 if (!token)
202 return;
203 if (token_type(token) != TOKEN_STREAMBEGIN)
204 return;
205 token = token->next;
206 while (token_type(token) != TOKEN_STREAMEND) {
207 if (token_type(token) != TOKEN_IDENT)
208 return;
209 func = show_ident(token->ident);
210 if (assign)
211 add_function_assign_hook(func, call_back, info);
212 else
213 add_function_hook(func, call_back, info);
214 token = token->next;
216 clear_token_alloc();
219 void register_func_hooks_from_file(const char *file,
220 func_hook *call_back, void *info)
222 register_funcs_from_file_helper(file, call_back, info, false);
225 void register_assign_hooks_from_file(const char *file,
226 func_hook *call_back, void *info)
228 register_funcs_from_file_helper(file, call_back, info, true);
231 void add_implied_return_hook(const char *look_for,
232 implied_return_hook *call_back,
233 void *info)
235 struct fcall_back *cb;
237 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
238 add_callback(func_hash, look_for, cb);
241 static void db_helper(struct expression *expr, param_key_hook *call_back, int param, const char *key, void *info)
243 char *name;
244 struct symbol *sym;
246 if (param == -2) {
247 call_back(expr, key, NULL, info);
248 return;
251 name = get_name_sym_from_param_key(expr, param, key, &sym);
252 if (!name || !sym)
253 goto free;
255 call_back(expr, name, sym, info);
256 free:
257 free_string(name);
260 static struct expression *get_parent_assignment(struct expression *expr)
262 struct expression *parent;
263 int cnt = 0;
265 parent = expr_get_fake_parent_expr(expr);
266 if (parent && parent->type == EXPR_ASSIGNMENT)
267 return parent;
269 parent = expr;
270 while (true) {
271 parent = expr_get_parent_expr(parent);
272 if (!parent || ++cnt >= 5)
273 break;
274 if (parent->type == EXPR_CAST)
275 continue;
276 if (parent->type == EXPR_PREOP && parent->op == '(')
277 continue;
278 break;
281 if (parent && parent->type == EXPR_ASSIGNMENT)
282 return parent;
283 return NULL;
286 static void param_key_function(const char *fn, struct expression *expr, void *data)
288 struct param_key_data *pkd = data;
289 struct expression *parent;
291 parent = get_parent_assignment(expr);
292 if (parent)
293 expr = parent;
295 db_helper(expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
298 static void param_key_implies_function(const char *fn, struct expression *call_expr,
299 struct expression *assign_expr, void *data)
301 struct param_key_data *pkd = data;
303 db_helper(assign_expr ?: call_expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
306 static struct param_key_data *alloc_pkd(param_key_hook *call_back, int param, const char *key, void *info)
308 struct param_key_data *pkd;
310 pkd = malloc(sizeof(*pkd));
311 pkd->call_back = call_back;
312 pkd->param = param;
313 pkd->key = alloc_string(key);
314 pkd->info = info;
316 return pkd;
319 void add_function_param_key_hook(const char *look_for, param_key_hook *call_back,
320 int param, const char *key, void *info)
322 struct param_key_data *pkd;
324 pkd = alloc_pkd(call_back, param, key, info);
325 add_function_hook(look_for, &param_key_function, pkd);
328 void add_function_param_key_hook_late(const char *look_for, param_key_hook *call_back,
329 int param, const char *key, void *info)
331 struct param_key_data *pkd;
333 pkd = alloc_pkd(call_back, param, key, info);
334 add_function_hook_late(look_for, &param_key_function, pkd);
337 void return_implies_param_key(const char *look_for, sval_t start, sval_t end,
338 param_key_hook *call_back,
339 int param, const char *key, void *info)
341 struct param_key_data *pkd;
343 pkd = alloc_pkd(call_back, param, key, info);
344 return_implies_state_sval(look_for, start, end, &param_key_implies_function, pkd);
347 void return_implies_param_key_exact(const char *look_for, sval_t start, sval_t end,
348 param_key_hook *call_back,
349 int param, const char *key, void *info)
351 struct param_key_data *pkd;
353 pkd = alloc_pkd(call_back, param, key, info);
354 return_implies_exact(look_for, start, end, &param_key_implies_function, pkd);
357 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
358 void *info)
360 struct fcall_back *cb;
362 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
363 add_callback(func_hash, look_for, cb);
366 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
367 void *info)
369 struct fcall_back *cb;
371 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
372 add_callback(func_hash, look_for, cb);
375 void return_implies_state(const char *look_for, long long start, long long end,
376 implication_hook *call_back, void *info)
378 struct fcall_back *cb;
380 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
381 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
382 add_callback(func_hash, look_for, cb);
385 void return_implies_state_sval(const char *look_for, sval_t start, sval_t end,
386 implication_hook *call_back, void *info)
388 struct fcall_back *cb;
390 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
391 cb->range = alloc_range_perm(start, end);
392 add_callback(func_hash, look_for, cb);
395 void return_implies_exact(const char *look_for, sval_t start, sval_t end,
396 implication_hook *call_back, void *info)
398 struct fcall_back *cb;
400 cb = alloc_fcall_back(RANGED_EXACT, call_back, info);
401 cb->range = alloc_range_perm(start, end);
402 add_callback(func_hash, look_for, cb);
405 static struct return_implies_callback *alloc_db_return_callback(int type, bool param_key, void *callback)
407 struct return_implies_callback *cb;
409 cb = __alloc_return_implies_callback(0);
410 cb->type = type;
411 cb->param_key = param_key;
412 cb->callback = callback;
414 return cb;
417 void select_return_states_hook(int type, return_implies_hook *callback)
419 struct return_implies_callback *cb;
421 cb = alloc_db_return_callback(type, false, callback);
422 add_ptr_list(&db_return_states_list, cb);
425 static void call_db_return_callback(struct db_callback_info *db_info,
426 struct return_implies_callback *cb,
427 int param, char *key, char *value)
429 if (cb->param_key) {
430 db_helper(db_info->expr, cb->pk_callback, param, key, NULL);
431 add_ptr_list(&db_info->called, cb);
432 } else {
433 cb->callback(db_info->expr, param, key, value);
437 void select_return_param_key(int type, param_key_hook *callback)
439 struct return_implies_callback *cb;
441 cb = alloc_db_return_callback(type, true, callback);
442 add_ptr_list(&db_return_states_list, cb);
445 void select_return_states_before(void_fn *fn)
447 add_ptr_list(&return_states_before, fn);
450 void select_return_states_after(void_fn *fn)
452 add_ptr_list(&return_states_after, fn);
455 void add_return_string_hook(string_hook *fn)
457 add_ptr_list(&return_string_hooks, fn);
460 static bool call_call_backs(struct call_back_list *list, int type,
461 const char *fn, struct expression *expr)
463 struct fcall_back *tmp;
464 bool handled = false;
466 FOR_EACH_PTR(list, tmp) {
467 if (tmp->type == type) {
468 (tmp->u.call_back)(fn, expr, tmp->info);
469 handled = true;
471 } END_FOR_EACH_PTR(tmp);
473 return handled;
476 static void call_function_hooks(struct expression *expr, enum fn_hook_type type)
478 struct call_back_list *call_backs;
479 const char *fn_name;
481 while (expr->type == EXPR_ASSIGNMENT)
482 expr = strip_expr(expr->right);
483 if (expr->type != EXPR_CALL)
484 return;
486 fn_name = get_fn_name(expr->fn);
487 call_backs = get_call_backs(fn_name);
488 if (!call_backs)
489 return;
491 call_call_backs(call_backs, type, fn_name, expr);
494 static void call_return_states_after_hooks(struct expression *expr)
496 call_void_fns(return_states_after);
497 __pass_to_client(expr, FUNCTION_CALL_HOOK_AFTER_DB);
498 call_function_hooks(expr, REGULAR_CALL_LATE);
501 static void call_ranged_call_backs(struct call_back_list *list,
502 const char *fn, struct expression *call_expr,
503 struct expression *assign_expr)
505 struct fcall_back *tmp;
507 FOR_EACH_PTR(list, tmp) {
508 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
509 } END_FOR_EACH_PTR(tmp);
512 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
513 struct data_range *drange)
515 struct call_back_list *ret = NULL;
516 struct fcall_back *tmp;
518 FOR_EACH_PTR(list, tmp) {
519 if (tmp->type != RANGED_CALL &&
520 tmp->type != RANGED_EXACT)
521 continue;
522 if (ranges_equiv(tmp->range, drange))
523 add_ptr_list(&ret, tmp);
524 } END_FOR_EACH_PTR(tmp);
525 return ret;
528 static bool in_list_exact_sval(struct range_list *list, struct data_range *drange)
530 struct data_range *tmp;
532 FOR_EACH_PTR(list, tmp) {
533 if (ranges_equiv(tmp, drange))
534 return true;
535 } END_FOR_EACH_PTR(tmp);
536 return false;
540 * The assign_ranged_funcs() function is called when we have no data from the DB.
542 static bool assign_ranged_funcs(const char *fn, struct expression *expr,
543 struct call_back_list *call_backs)
545 struct fcall_back *tmp;
546 struct sm_state *sm;
547 char *var_name;
548 struct symbol *sym;
549 struct smatch_state *estate;
550 struct stree *tmp_stree;
551 struct stree *final_states = NULL;
552 struct range_list *handled_ranges = NULL;
553 struct range_list *unhandled_rl;
554 struct call_back_list *same_range_call_backs = NULL;
555 struct expression *call;
556 struct range_list *rl;
557 int handled = false;
559 if (!call_backs)
560 return false;
562 var_name = expr_to_var_sym(expr->left, &sym);
563 if (!var_name || !sym)
564 goto free;
566 call = strip_expr(expr->right);
568 FOR_EACH_PTR(call_backs, tmp) {
569 if (tmp->type != RANGED_CALL &&
570 tmp->type != RANGED_EXACT)
571 continue;
573 if (in_list_exact_sval(handled_ranges, tmp->range))
574 continue;
575 __push_fake_cur_stree();
576 tack_on(&handled_ranges, tmp->range);
578 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
579 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
580 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
582 rl = alloc_rl(tmp->range->min, tmp->range->max);
583 rl = cast_rl(get_type(expr->left), rl);
584 estate = alloc_estate_rl(rl);
585 set_extra_mod(var_name, sym, expr->left, estate);
587 tmp_stree = __pop_fake_cur_stree();
588 merge_fake_stree(&final_states, tmp_stree);
589 free_stree(&tmp_stree);
590 handled = true;
591 } END_FOR_EACH_PTR(tmp);
593 unhandled_rl = rl_filter(alloc_whole_rl(get_type(call)), handled_ranges);
594 if (unhandled_rl) {
595 __push_fake_cur_stree();
596 rl = cast_rl(get_type(expr->left), unhandled_rl);
597 estate = alloc_estate_rl(rl);
598 set_extra_mod(var_name, sym, expr->left, estate);
599 tmp_stree = __pop_fake_cur_stree();
600 merge_fake_stree(&final_states, tmp_stree);
601 free_stree(&tmp_stree);
604 FOR_EACH_SM(final_states, sm) {
605 __set_sm(sm);
606 } END_FOR_EACH_SM(sm);
608 free_stree(&final_states);
609 free:
610 free_string(var_name);
611 return handled;
614 static void call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left, struct stree **implied_true, struct stree **implied_false)
616 struct call_back_list *call_backs;
617 struct fcall_back *tmp;
618 const char *fn_name;
619 struct data_range *value_range;
620 struct stree *true_states = NULL;
621 struct stree *false_states = NULL;
622 struct stree *tmp_stree;
624 *implied_true = NULL;
625 *implied_false = NULL;
626 fn_name = get_fn_name(expr->fn);
627 call_backs = get_call_backs(fn_name);
628 if (!call_backs)
629 return;
630 value_range = alloc_range(sval, sval);
632 /* set true states */
633 __push_fake_cur_stree();
634 FOR_EACH_PTR(call_backs, tmp) {
635 if (tmp->type != RANGED_CALL &&
636 tmp->type != RANGED_EXACT)
637 continue;
638 if (!true_comparison_range_LR(comparison, tmp->range, value_range, left))
639 continue;
640 (tmp->u.ranged)(fn_name, expr, NULL, tmp->info);
641 } END_FOR_EACH_PTR(tmp);
642 tmp_stree = __pop_fake_cur_stree();
643 merge_fake_stree(&true_states, tmp_stree);
644 free_stree(&tmp_stree);
646 /* set false states */
647 __push_fake_cur_stree();
648 FOR_EACH_PTR(call_backs, tmp) {
649 if (tmp->type != RANGED_CALL &&
650 tmp->type != RANGED_EXACT)
651 continue;
652 if (!false_comparison_range_LR(comparison, tmp->range, value_range, left))
653 continue;
654 (tmp->u.ranged)(fn_name, expr, NULL, tmp->info);
655 } END_FOR_EACH_PTR(tmp);
656 tmp_stree = __pop_fake_cur_stree();
657 merge_fake_stree(&false_states, tmp_stree);
658 free_stree(&tmp_stree);
660 *implied_true = true_states;
661 *implied_false = false_states;
664 static void set_implied_states(struct db_callback_info *db_info)
666 struct sm_state *sm;
668 FOR_EACH_SM(db_info->implied, sm) {
669 __set_sm(sm);
670 } END_FOR_EACH_SM(sm);
672 free_stree(&db_info->implied);
675 static void store_return_state(struct db_callback_info *db_info, const char *ret_str, struct smatch_state *state)
677 db_info->ret_str = alloc_sname(ret_str),
678 db_info->ret_state = state;
681 static bool fake_a_param_assignment(struct expression *expr, const char *ret_str, struct smatch_state *orig)
683 struct expression *arg, *left, *right, *tmp, *fake_assign;
684 char *p;
685 int param;
686 char buf[256];
687 char *str;
689 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
690 return false;
691 left = expr->left;
692 right = expr->right;
694 while (right->type == EXPR_ASSIGNMENT)
695 right = strip_expr(right->right);
696 if (!right || right->type != EXPR_CALL)
697 return false;
699 p = strchr(ret_str, '[');
700 if (!p)
701 return false;
703 p++;
704 if (p[0] == '=' && p[1] == '=')
705 p += 2;
706 if (p[0] != '$')
707 return false;
709 snprintf(buf, sizeof(buf), "%s", p);
711 p = buf;
712 p += 1;
713 param = strtol(p, &p, 10);
715 p = strchr(p, ']');
716 if (!p || *p != ']')
717 return false;
718 *p = '\0';
720 arg = get_argument_from_call_expr(right->args, param);
721 if (!arg)
722 return false;
724 /* There should be a get_other_name() function which returns an expr */
725 tmp = get_assigned_expr(arg);
726 if (tmp)
727 arg = tmp;
730 * This is a sanity check to prevent side effects from evaluating stuff
731 * twice.
733 str = expr_to_chunk_sym_vsl(arg, NULL, NULL);
734 if (!str)
735 return false;
736 free_string(str);
738 right = gen_expression_from_key(arg, buf);
739 if (!right) /* Mostly fails for binops like [$0 + 4032] */
740 return false;
741 fake_assign = assign_expression(left, '=', right);
742 __in_fake_parameter_assign++;
743 __split_expr(fake_assign);
744 __in_fake_parameter_assign--;
747 * If the return is "0-65531[$0->nla_len - 4]" the faked expression
748 * is maybe (-4)-65531 but we know it is in the 0-65531 range so both
749 * parts have to be considered. We use _nomod() because it's not really
750 * another modification, it's just a clarification.
753 if (estate_rl(orig)) {
754 struct smatch_state *faked;
755 struct range_list *rl;
757 faked = get_extra_state(left);
758 if (estate_rl(faked)) {
759 rl = rl_intersection(estate_rl(faked), estate_rl(orig));
760 if (rl)
761 set_extra_expr_nomod(expr, alloc_estate_rl(rl));
765 return true;
768 static void fake_return_assignment(struct db_callback_info *db_info, int type, int param, char *key, char *value)
770 struct expression *call, *left, *right, *assign;
771 int right_param;
773 if (type != PARAM_COMPARE)
774 return;
776 call = db_info->expr;
777 while (call && call->type == EXPR_ASSIGNMENT)
778 call = strip_expr(call->right);
779 if (!call || call->type != EXPR_CALL)
780 return;
782 // TODO: This only handles "$->foo = arg" and not "$->foo = arg->bar".
783 if (param != -1)
784 return;
785 if (!value || strncmp(value, "== $", 4) != 0)
786 return;
787 if (!isdigit(value[4]) || value[5] != '\0')
788 return;
789 right_param = atoi(value + 4);
791 left = gen_expr_from_param_key(db_info->expr, param, key);
792 if (!left)
793 return;
794 right = get_argument_from_call_expr(call->args, right_param);
796 assign = assign_expression(left, '=', right);
797 push_expression(&db_info->fake_param_assign_stack, assign);
800 static void set_fresh_mtag_returns(struct db_callback_info *db_info)
802 struct expression *expr = db_info->expr->left;
803 struct smatch_state *state;
805 if (!db_info->ret_state)
806 return;
808 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
809 state = get_mtag_return(db_info->expr, state);
810 if (!state)
811 return;
813 set_real_absolute(expr, state);
814 set_extra_expr_mod(expr, state);
816 db_info->ret_state = NULL;
817 db_info->ret_str = NULL;
820 static void set_return_assign_state(struct db_callback_info *db_info)
822 struct expression *expr = db_info->expr->left;
823 struct expression *fake_assign;
824 struct smatch_state *state;
826 if (!db_info->ret_state)
827 return;
829 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
830 if (!fake_a_param_assignment(db_info->expr, db_info->ret_str, state))
831 set_extra_expr_mod(expr, state);
833 while ((fake_assign = pop_expression(&db_info->fake_param_assign_stack))) {
834 struct range_list *left, *right;
837 * Originally, I tried to do this as a assignment to record that
838 * a = frob(b) implies that "a->foo == b->foo" etc. But that
839 * caused a problem because then it was recorded that "a->foo"
840 * was modified and recorded as a PARAM_SET in the database.
842 * So now, instead of faking an assignment we use
843 * set_extra_expr_nomod() but it's still recorded as an
844 * assignment in the ->fake_param_assign_stack for legacy
845 * reasons and because it's a handy way to store a left/right
846 * pair.
849 get_absolute_rl(fake_assign->left, &left);
850 get_absolute_rl(fake_assign->right, &right);
851 right = cast_rl(get_type(fake_assign->left), right);
852 // FIXME: add some sanity checks
853 // FIXME: preserve the sm state if possible
854 set_extra_expr_nomod(fake_assign->left, alloc_estate_rl(right));
858 static void set_other_side_state(struct db_callback_info *db_info)
860 struct expression *expr = db_info->var_expr;
861 struct smatch_state *state;
863 if (!db_info->ret_state)
864 return;
866 // TODO: faked_assign set ==$ equiv here
868 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
869 set_extra_expr_nomod(expr, state);
870 db_info->ret_state = NULL;
871 db_info->ret_str = NULL;
874 static void handle_ret_equals_param(char *ret_string, struct range_list *rl, struct expression *call)
876 char *str;
877 long long param;
878 struct expression *arg;
879 struct range_list *orig;
881 // TODO: faked_assign This needs to be handled in the assignment code
883 str = strstr(ret_string, "==$");
884 if (!str)
885 return;
886 str += 3;
887 param = strtoll(str, NULL, 10);
888 arg = get_argument_from_call_expr(call->args, param);
889 if (!arg)
890 return;
891 get_absolute_rl(arg, &orig);
892 rl = rl_intersection(orig, rl);
893 if (!rl)
894 return;
895 set_extra_expr_nomod(arg, alloc_estate_rl(rl));
898 static bool impossible_limit(struct db_callback_info *db_info, int param, char *key, char *value)
900 struct expression *expr = db_info->expr;
901 struct expression *arg;
902 struct smatch_state *state;
903 struct range_list *passed;
904 struct range_list *limit;
905 struct symbol *compare_type;
907 while (expr->type == EXPR_ASSIGNMENT)
908 expr = strip_expr(expr->right);
909 if (expr->type != EXPR_CALL)
910 return false;
912 arg = get_argument_from_call_expr(expr->args, param);
913 if (!arg)
914 return false;
916 if (strcmp(key, "$") == 0) {
917 if (!get_implied_rl(arg, &passed))
918 return false;
920 compare_type = get_arg_type(expr->fn, param);
921 } else {
922 char *name;
923 struct symbol *sym;
925 name = get_variable_from_key(arg, key, &sym);
926 if (!name || !sym)
927 return false;
929 state = get_state(SMATCH_EXTRA, name, sym);
930 if (!state) {
931 free_string(name);
932 return false;
934 passed = estate_rl(state);
935 if (!passed || is_whole_rl(passed)) {
936 free_string(name);
937 return false;
940 compare_type = get_member_type_from_key(arg, key);
943 passed = cast_rl(compare_type, passed);
944 call_results_to_rl(expr, compare_type, value, &limit);
945 if (!limit || is_whole_rl(limit))
946 return false;
947 if (possibly_true_rl(passed, SPECIAL_EQUAL, limit))
948 return false;
949 if (option_debug || local_debug || debug_db)
950 sm_msg("impossible: %d '%s' limit '%s' == '%s' return='%s'", param, key, show_rl(passed), value, db_info->ret_str);
951 return true;
954 static bool is_impossible_data(int type, struct db_callback_info *db_info, int param, char *key, char *value)
956 if (type == PARAM_LIMIT && impossible_limit(db_info, param, key, value))
957 return true;
958 if (type == COMPARE_LIMIT && param_compare_limit_is_impossible(db_info->expr, param, key, value)) {
959 if (local_debug || debug_db)
960 sm_msg("param_compare_limit_is_impossible: %d %s %s", param, key, value);
961 return true;
963 return false;
966 static bool func_type_mismatch(struct expression *expr, const char *value)
968 struct symbol *type;
970 /* This makes faking returns easier */
971 if (!value || value[0] == '\0')
972 return false;
974 while (expr->type == EXPR_ASSIGNMENT)
975 expr = strip_expr(expr->right);
978 * Short cut: We only care about function pointers that are struct
979 * members.
982 if (expr->fn->type == EXPR_SYMBOL)
983 return false;
985 type = get_type(expr->fn);
986 if (!type)
987 return false;
988 if (type->type == SYM_PTR)
989 type = get_real_base_type(type);
991 if (strcmp(type_to_str(type), value) == 0)
992 return false;
994 return true;
997 static void process_return_states(struct db_callback_info *db_info)
999 struct stree *stree;
1001 set_implied_states(db_info);
1002 free_ptr_list(&db_info->called);
1003 stree = __pop_fake_cur_stree();
1004 if (debug_db) {
1005 sm_msg("States from DB: %s expr='%s' ret_str='%s' rl='%s' state='%s'",
1006 db_info->cull ? "Culling" : "Merging",
1007 expr_to_str(db_info->expr),
1008 db_info->ret_str, show_rl(db_info->rl),
1009 db_info->ret_state ? db_info->ret_state->name : "<none>");
1010 __print_stree(stree);
1013 if (!db_info->cull)
1014 merge_fake_stree(&db_info->stree, stree);
1015 free_stree(&stree);
1017 db_info->ret_state = NULL;
1018 db_info->ret_str = NULL;
1021 static int db_compare_callback(void *_info, int argc, char **argv, char **azColName)
1023 struct db_callback_info *db_info = _info;
1024 struct range_list *var_rl = db_info->rl;
1025 struct range_list *ret_range;
1026 int type, param;
1027 char *ret_str, *key, *value;
1028 struct return_implies_callback *tmp;
1029 int return_id;
1030 int comparison;
1032 if (argc != 6)
1033 return 0;
1035 return_id = atoi(argv[0]);
1036 ret_str = argv[1];
1037 type = atoi(argv[2]);
1038 param = atoi(argv[3]);
1039 key = argv[4];
1040 value = argv[5];
1042 db_info->has_states = 1;
1043 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1044 set_other_side_state(db_info);
1045 process_return_states(db_info);
1046 __push_fake_cur_stree();
1047 db_info->cull = 0;
1049 db_info->prev_return_id = return_id;
1051 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1052 db_info->cull = 1;
1053 if (db_info->cull)
1054 return 0;
1055 if (type == CULL_PATH) {
1056 db_info->cull = 1;
1057 return 0;
1060 if (is_impossible_data(type, db_info, param, key, value)) {
1061 db_info->cull = 1;
1062 return 0;
1065 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1066 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1067 if (!ret_range)
1068 ret_range = alloc_whole_rl(get_type(db_info->expr));
1070 comparison = db_info->comparison;
1071 if (db_info->left)
1072 comparison = flip_comparison(comparison);
1074 if (db_info->true_side) {
1075 if (!possibly_true_rl(var_rl, comparison, ret_range))
1076 return 0;
1077 if (type == PARAM_LIMIT)
1078 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1079 else if (type > PARAM_LIMIT)
1080 set_implied_states(db_info);
1081 filter_by_comparison(&var_rl, comparison, ret_range);
1082 filter_by_comparison(&ret_range, flip_comparison(comparison), var_rl);
1083 } else {
1084 if (!possibly_false_rl(var_rl, comparison, ret_range))
1085 return 0;
1086 if (type == PARAM_LIMIT)
1087 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1088 else if (type > PARAM_LIMIT)
1089 set_implied_states(db_info);
1090 filter_by_comparison(&var_rl, negate_comparison(comparison), ret_range);
1091 filter_by_comparison(&ret_range, flip_comparison(negate_comparison(comparison)), var_rl);
1094 handle_ret_equals_param(ret_str, ret_range, db_info->expr);
1096 if (type == INTERNAL) {
1097 set_state(-1, "unnull_path", NULL, &true_state);
1098 call_string_hooks(return_string_hooks, db_info->expr, ret_str);
1099 store_return_state(db_info, ret_str, alloc_estate_rl(clone_rl(var_rl)));
1102 FOR_EACH_PTR(db_info->callbacks, tmp) {
1103 if (tmp->type == type)
1104 call_db_return_callback(db_info, tmp, param, key, value);
1105 } END_FOR_EACH_PTR(tmp);
1107 fake_return_assignment(db_info, type, param, key, value);
1109 return 0;
1112 static void compare_db_return_states_callbacks(struct expression *left, int comparison, struct expression *right, struct stree *implied_true, struct stree *implied_false)
1114 struct stree *orig_states;
1115 struct stree *true_states;
1116 struct stree *false_states;
1117 struct sm_state *sm;
1118 struct db_callback_info db_info = {};
1119 struct expression *var_expr;
1120 struct expression *call_expr;
1121 struct range_list *rl;
1122 int call_on_left;
1124 orig_states = clone_stree(__get_cur_stree());
1126 /* legacy cruft. need to fix call_implies_callbacks(). */
1127 call_on_left = 1;
1128 call_expr = left;
1129 var_expr = right;
1130 if (left->type != EXPR_CALL) {
1131 call_on_left = 0;
1132 call_expr = right;
1133 var_expr = left;
1136 get_absolute_rl(var_expr, &rl);
1138 db_info.comparison = comparison;
1139 db_info.expr = call_expr;
1140 db_info.rl = rl;
1141 db_info.left = call_on_left;
1142 db_info.callbacks = db_return_states_list;
1143 db_info.var_expr = var_expr;
1145 call_void_fns(return_states_before);
1147 db_info.true_side = 1;
1148 db_info.stree = NULL;
1149 db_info.prev_return_id = -1;
1150 __push_fake_cur_stree();
1151 sql_select_return_states("return_id, return, type, parameter, key, value",
1152 call_expr, db_compare_callback, &db_info);
1153 set_other_side_state(&db_info);
1154 process_return_states(&db_info);
1155 true_states = db_info.stree;
1156 if (!true_states && db_info.has_states) {
1157 __push_fake_cur_stree();
1158 set_path_impossible();
1159 true_states = __pop_fake_cur_stree();
1162 nullify_path();
1163 __unnullify_path();
1164 FOR_EACH_SM(orig_states, sm) {
1165 __set_sm_cur_stree(sm);
1166 } END_FOR_EACH_SM(sm);
1168 db_info.true_side = 0;
1169 db_info.stree = NULL;
1170 db_info.prev_return_id = -1;
1171 db_info.cull = 0;
1172 __push_fake_cur_stree();
1173 sql_select_return_states("return_id, return, type, parameter, key, value", call_expr,
1174 db_compare_callback, &db_info);
1175 set_other_side_state(&db_info);
1176 process_return_states(&db_info);
1177 false_states = db_info.stree;
1178 if (!false_states && db_info.has_states) {
1179 __push_fake_cur_stree();
1180 set_path_impossible();
1181 false_states = __pop_fake_cur_stree();
1184 nullify_path();
1185 __unnullify_path();
1186 FOR_EACH_SM(orig_states, sm) {
1187 __set_sm_cur_stree(sm);
1188 } END_FOR_EACH_SM(sm);
1190 free_stree(&orig_states);
1192 FOR_EACH_SM(true_states, sm) {
1193 __set_true_false_sm(sm, NULL);
1194 } END_FOR_EACH_SM(sm);
1195 FOR_EACH_SM(false_states, sm) {
1196 __set_true_false_sm(NULL, sm);
1197 } END_FOR_EACH_SM(sm);
1199 free_stree(&true_states);
1200 free_stree(&false_states);
1202 call_return_states_after_hooks(call_expr);
1204 FOR_EACH_SM(implied_true, sm) {
1205 __set_true_false_sm(sm, NULL);
1206 } END_FOR_EACH_SM(sm);
1207 FOR_EACH_SM(implied_false, sm) {
1208 __set_true_false_sm(NULL, sm);
1209 } END_FOR_EACH_SM(sm);
1212 void function_comparison(struct expression *left, int comparison, struct expression *right)
1214 struct expression *var_expr;
1215 struct expression *call_expr;
1216 struct stree *implied_true = NULL;
1217 struct stree *implied_false = NULL;
1218 struct range_list *rl;
1219 sval_t sval;
1220 int call_on_left;
1222 // TODO: faked_assign delete this
1223 // condition calls should be faked and then handled as assignments
1224 // this code is a lazy work around
1226 if (unreachable())
1227 return;
1229 /* legacy cruft. need to fix call_implies_callbacks(). */
1230 call_on_left = 1;
1231 call_expr = left;
1232 var_expr = right;
1233 if (left->type != EXPR_CALL) {
1234 call_on_left = 0;
1235 call_expr = right;
1236 var_expr = left;
1239 get_absolute_rl(var_expr, &rl);
1241 if (rl_to_sval(rl, &sval))
1242 call_implies_callbacks(comparison, call_expr, sval, call_on_left, &implied_true, &implied_false);
1244 compare_db_return_states_callbacks(left, comparison, right, implied_true, implied_false);
1245 free_stree(&implied_true);
1246 free_stree(&implied_false);
1249 static void call_ranged_return_hooks(struct db_callback_info *db_info)
1251 struct call_back_list *call_backs;
1252 struct range_list *range_rl;
1253 struct expression *expr;
1254 struct fcall_back *tmp;
1255 const char *fn_name;
1257 expr = strip_expr(db_info->expr);
1258 while (expr->type == EXPR_ASSIGNMENT)
1259 expr = strip_expr(expr->right);
1260 if (expr->type != EXPR_CALL)
1261 return;
1263 fn_name = get_fn_name(expr->fn);
1264 call_backs = get_call_backs(fn_name);
1265 FOR_EACH_PTR(call_backs, tmp) {
1266 if (tmp->type != RANGED_CALL)
1267 continue;
1268 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1269 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1270 if (possibly_true_rl(range_rl, SPECIAL_EQUAL, estate_rl(db_info->ret_state)))
1271 (tmp->u.ranged)(fn_name, expr, db_info->expr, tmp->info);
1272 } END_FOR_EACH_PTR(tmp);
1274 FOR_EACH_PTR(call_backs, tmp) {
1275 if (tmp->type != RANGED_EXACT)
1276 continue;
1277 if (!estate_rl(db_info->ret_state))
1278 continue;
1280 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1281 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1284 * If there is an returned value out of range then this is not
1285 * an exact match. In other words, "0,4096-ptr_max" is not
1286 * necessarily a valid match.
1289 if (remove_range(estate_rl(db_info->ret_state),
1290 rl_min(range_rl), rl_max(range_rl)))
1291 continue;
1292 (tmp->u.ranged)(fn_name, expr, db_info->expr, tmp->info);
1293 } END_FOR_EACH_PTR(tmp);
1296 static int db_assign_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1298 struct db_callback_info *db_info = _info;
1299 struct range_list *ret_range;
1300 int type, param;
1301 char *ret_str, *key, *value;
1302 struct return_implies_callback *tmp;
1303 int return_id;
1305 if (argc != 6)
1306 return 0;
1308 return_id = atoi(argv[0]);
1309 ret_str = argv[1];
1310 type = atoi(argv[2]);
1311 param = atoi(argv[3]);
1312 key = argv[4];
1313 value = argv[5];
1315 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1316 call_ranged_return_hooks(db_info);
1317 set_return_assign_state(db_info);
1318 process_return_states(db_info);
1319 __push_fake_cur_stree();
1320 db_info->cull = 0;
1322 db_info->prev_return_id = return_id;
1324 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1325 db_info->cull = 1;
1326 if (db_info->cull)
1327 return 0;
1328 if (type == CULL_PATH) {
1329 db_info->cull = 1;
1330 return 0;
1332 if (is_impossible_data(type, db_info, param, key, value)) {
1333 db_info->cull = 1;
1334 return 0;
1337 if (type == PARAM_LIMIT)
1338 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1339 else if (type > PARAM_LIMIT)
1340 set_implied_states(db_info);
1342 db_info->handled = 1;
1343 call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), ret_str, &ret_range);
1344 if (!ret_range)
1345 ret_range = alloc_whole_rl(get_type(strip_expr(db_info->expr->right)));
1346 ret_range = cast_rl(get_type(db_info->expr->right), ret_range);
1348 if (type == INTERNAL) {
1349 set_state(-1, "unnull_path", NULL, &true_state);
1350 __add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), ret_str);
1351 call_string_hooks(return_string_hooks, db_info->expr, ret_str);
1352 store_return_state(db_info, ret_str, alloc_estate_rl(ret_range));
1353 set_fresh_mtag_returns(db_info);
1356 FOR_EACH_PTR(db_return_states_list, tmp) {
1357 if (tmp->type == type)
1358 call_db_return_callback(db_info, tmp, param, key, value);
1359 } END_FOR_EACH_PTR(tmp);
1361 fake_return_assignment(db_info, type, param, key, value);
1363 return 0;
1366 static int db_return_states_assign(struct expression *expr)
1368 struct expression *right;
1369 struct sm_state *sm;
1370 struct db_callback_info db_info = {};
1372 right = strip_expr(expr->right);
1374 db_info.prev_return_id = -1;
1375 db_info.expr = expr;
1376 db_info.stree = NULL;
1377 db_info.handled = 0;
1379 call_void_fns(return_states_before);
1381 __push_fake_cur_stree();
1382 sql_select_return_states("return_id, return, type, parameter, key, value",
1383 right, db_assign_return_states_callback, &db_info);
1384 if (option_debug) {
1385 sm_msg("%s return_id %d return_ranges %s",
1386 db_info.cull ? "culled" : "merging",
1387 db_info.prev_return_id,
1388 db_info.ret_state ? db_info.ret_state->name : "'<empty>'");
1390 if (db_info.handled)
1391 call_ranged_return_hooks(&db_info);
1392 set_return_assign_state(&db_info);
1393 process_return_states(&db_info);
1395 if (!db_info.stree && db_info.cull) { /* this means we culled everything */
1396 set_extra_expr_mod(expr->left, alloc_estate_whole(get_type(expr->left)));
1397 set_path_impossible();
1399 FOR_EACH_SM(db_info.stree, sm) {
1400 __set_sm(sm);
1401 } END_FOR_EACH_SM(sm);
1403 free_stree(&db_info.stree);
1404 call_return_states_after_hooks(right);
1406 return db_info.handled;
1409 static bool handle_implied_return(struct expression *expr)
1411 struct range_list *rl;
1413 if (!get_implied_return(expr->right, &rl))
1414 return false;
1415 rl = cast_rl(get_type(expr->left), rl);
1416 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1417 return true;
1420 static void match_assign_call(struct expression *expr)
1422 struct call_back_list *call_backs;
1423 const char *fn_name;
1424 struct expression *right;
1425 int handled = 0;
1426 struct range_list *rl;
1428 if (expr->op != '=')
1429 return;
1431 right = strip_expr(expr->right);
1432 if (is_fake_call(right))
1433 return;
1435 fn_name = get_fn_name(right->fn);
1436 call_backs = get_call_backs(fn_name);
1439 * The ordering here is sort of important.
1440 * One example, of how this matters is that when we do:
1442 * len = strlen(str);
1444 * That is handled by smatch_common_functions.c and smatch_strlen.c.
1445 * They use implied_return and function_assign_hook respectively.
1446 * We want to get the implied return first before we do the function
1447 * assignment hook otherwise we end up writing the wrong thing for len
1448 * in smatch_extra.c because we assume that it already holds the
1449 * strlen() when we haven't set it yet.
1452 if (db_return_states_assign(expr))
1453 handled = 1;
1454 else
1455 handled = assign_ranged_funcs(fn_name, expr, call_backs);
1456 handled |= handle_implied_return(expr);
1459 call_call_backs(call_backs, ASSIGN_CALL, fn_name, expr);
1461 if (handled)
1462 return;
1464 /* assignment wasn't handled at all */
1465 get_absolute_rl(expr->right, &rl);
1466 rl = cast_rl(get_type(expr->left), rl);
1467 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1470 static int db_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1472 struct db_callback_info *db_info = _info;
1473 struct range_list *ret_range;
1474 int type, param;
1475 char *ret_str, *key, *value;
1476 struct return_implies_callback *tmp;
1477 int return_id;
1479 if (argc != 6)
1480 return 0;
1482 return_id = atoi(argv[0]);
1483 ret_str = argv[1];
1484 type = atoi(argv[2]);
1485 param = atoi(argv[3]);
1486 key = argv[4];
1487 value = argv[5];
1489 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1490 call_ranged_return_hooks(db_info);
1491 process_return_states(db_info);
1492 __push_fake_cur_stree();
1493 __unnullify_path();
1494 db_info->cull = 0;
1496 db_info->prev_return_id = return_id;
1498 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1499 db_info->cull = 1;
1500 if (db_info->cull)
1501 return 0;
1502 if (type == CULL_PATH) {
1503 db_info->cull = 1;
1504 return 0;
1506 if (is_impossible_data(type, db_info, param, key, value)) {
1507 db_info->cull = 1;
1508 return 0;
1511 if (type == PARAM_LIMIT)
1512 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1513 else if (type > PARAM_LIMIT)
1514 set_implied_states(db_info);
1516 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1517 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1519 if (type == INTERNAL) {
1520 struct smatch_state *state;
1522 set_state(-1, "unnull_path", NULL, &true_state);
1523 call_string_hooks(return_string_hooks, db_info->expr, ret_str);
1524 state = alloc_estate_rl(ret_range);
1525 store_return_state(db_info, ret_str, state);
1528 FOR_EACH_PTR(db_return_states_list, tmp) {
1529 if (tmp->type == type)
1530 call_db_return_callback(db_info, tmp, param, key, value);
1531 } END_FOR_EACH_PTR(tmp);
1533 fake_return_assignment(db_info, type, param, key, value);
1535 return 0;
1538 static void db_return_states(struct expression *expr)
1540 struct sm_state *sm;
1541 struct db_callback_info db_info = {};
1543 if (!__get_cur_stree()) /* no return functions */
1544 return;
1546 db_info.prev_return_id = -1;
1547 db_info.expr = expr;
1548 db_info.stree = NULL;
1550 call_void_fns(return_states_before);
1552 __push_fake_cur_stree();
1553 __unnullify_path();
1554 sql_select_return_states("return_id, return, type, parameter, key, value",
1555 expr, db_return_states_callback, &db_info);
1556 call_ranged_return_hooks(&db_info);
1557 process_return_states(&db_info);
1559 FOR_EACH_SM(db_info.stree, sm) {
1560 __set_sm(sm);
1561 } END_FOR_EACH_SM(sm);
1563 free_stree(&db_info.stree);
1564 call_return_states_after_hooks(expr);
1567 static void db_return_states_call(struct expression *expr)
1569 if (unreachable())
1570 return;
1572 if (is_assigned_call(expr) || is_fake_assigned_call(expr))
1573 return;
1574 if (is_condition_call(expr))
1575 return;
1576 db_return_states(expr);
1579 static void match_function_call(struct expression *expr)
1581 call_function_hooks(expr, REGULAR_CALL);
1582 db_return_states_call(expr);
1585 static void match_macro_assign(struct expression *expr)
1587 struct call_back_list *call_backs;
1588 const char *macro;
1589 struct expression *right;
1591 right = strip_expr(expr->right);
1592 macro = get_macro_name(right->pos);
1593 call_backs = search_callback(func_hash, (char *)macro);
1594 if (!call_backs)
1595 return;
1596 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
1597 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
1600 bool get_implied_return(struct expression *expr, struct range_list **rl)
1602 struct call_back_list *call_backs;
1603 struct fcall_back *tmp;
1604 bool handled = false;
1605 char *fn;
1607 *rl = NULL;
1609 expr = strip_expr(expr);
1610 fn = expr_to_var(expr->fn);
1611 if (!fn)
1612 goto out;
1614 call_backs = search_callback(func_hash, fn);
1616 FOR_EACH_PTR(call_backs, tmp) {
1617 if (tmp->type == IMPLIED_RETURN)
1618 handled |= (tmp->u.implied_return)(expr, tmp->info, rl);
1619 } END_FOR_EACH_PTR(tmp);
1621 out:
1622 free_string(fn);
1623 return handled;
1626 struct range_list *get_range_implications(const char *fn)
1628 struct call_back_list *call_backs;
1629 struct range_list *ret = NULL;
1630 struct fcall_back *tmp;
1632 call_backs = search_callback(func_hash, (char *)fn);
1634 FOR_EACH_PTR(call_backs, tmp) {
1635 if (tmp->type != RANGED_CALL &&
1636 tmp->type != RANGED_EXACT)
1637 continue;
1638 add_ptr_list(&ret, tmp->range);
1639 } END_FOR_EACH_PTR(tmp);
1641 return ret;
1644 void create_function_hook_hash(void)
1646 func_hash = create_function_hashtable(5000);
1649 void register_function_hooks(int id)
1651 add_hook(&match_function_call, CALL_HOOK_AFTER_INLINE);
1652 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
1653 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);