validation: delete obsolete dev_hold() check
[smatch.git] / smatch_function_hooks.c
blob099487f839e37796482bf5c264a450c701c01069
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 typedef void (void_fn)(void);
114 DECLARE_PTR_LIST(void_fn_list, void_fn *);
115 static struct void_fn_list *return_states_before;
116 static struct void_fn_list *return_states_after;
118 struct db_callback_info {
119 int true_side;
120 int comparison;
121 struct expression *expr;
122 struct range_list *rl;
123 int left;
124 struct stree *stree;
125 struct stree *implied;
126 struct db_implies_list *callbacks;
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 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
151 struct fcall_back *cb;
153 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
154 add_callback(func_hash, look_for, cb);
157 void add_function_hook_late(const char *look_for, func_hook *call_back, void *info)
159 struct fcall_back *cb;
161 cb = alloc_fcall_back(REGULAR_CALL_LATE, call_back, info);
162 add_callback(func_hash, look_for, cb);
165 void add_function_assign_hook(const char *look_for, func_hook *call_back,
166 void *info)
168 struct fcall_back *cb;
170 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
171 add_callback(func_hash, look_for, cb);
174 static void register_funcs_from_file_helper(const char *file,
175 func_hook *call_back, void *info,
176 bool assign)
178 struct token *token;
179 const char *func;
180 char name[64];
182 snprintf(name, sizeof(name), "%s.%s", option_project_str, file);
183 token = get_tokens_file(name);
184 if (!token)
185 return;
186 if (token_type(token) != TOKEN_STREAMBEGIN)
187 return;
188 token = token->next;
189 while (token_type(token) != TOKEN_STREAMEND) {
190 if (token_type(token) != TOKEN_IDENT)
191 return;
192 func = show_ident(token->ident);
193 if (assign)
194 add_function_assign_hook(func, call_back, info);
195 else
196 add_function_hook(func, call_back, info);
197 token = token->next;
199 clear_token_alloc();
202 void register_func_hooks_from_file(const char *file,
203 func_hook *call_back, void *info)
205 register_funcs_from_file_helper(file, call_back, info, false);
208 void register_assign_hooks_from_file(const char *file,
209 func_hook *call_back, void *info)
211 register_funcs_from_file_helper(file, call_back, info, true);
214 void add_implied_return_hook(const char *look_for,
215 implied_return_hook *call_back,
216 void *info)
218 struct fcall_back *cb;
220 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
221 add_callback(func_hash, look_for, cb);
224 static void db_helper(struct expression *expr, param_key_hook *call_back, int param, const char *key, void *info)
226 char *name;
227 struct symbol *sym;
229 if (param == -2) {
230 call_back(expr, key, NULL, info);
231 return;
234 name = get_name_sym_from_key(expr, param, key, &sym);
235 if (!name || !sym)
236 goto free;
238 call_back(expr, name, sym, info);
239 free:
240 free_string(name);
243 static void param_key_function(const char *fn, struct expression *expr, void *data)
245 struct param_key_data *pkd = data;
246 struct expression *parent;
247 int cnt = 0;
249 parent = expr;
250 while (true) {
251 parent = expr_get_parent_expr(parent);
252 if (!parent || ++cnt >= 5)
253 break;
254 if (parent->type == EXPR_CAST)
255 continue;
256 if (parent->type == EXPR_PREOP && parent->op == '(')
257 continue;
258 break;
261 if (parent && parent->type == EXPR_ASSIGNMENT)
262 expr = parent;
264 db_helper(expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
267 static void param_key_implies_function(const char *fn, struct expression *call_expr,
268 struct expression *assign_expr, void *data)
270 struct param_key_data *pkd = data;
272 db_helper(assign_expr ?: call_expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
275 static struct param_key_data *alloc_pkd(param_key_hook *call_back, int param, const char *key, void *info)
277 struct param_key_data *pkd;
279 pkd = malloc(sizeof(*pkd));
280 pkd->call_back = call_back;
281 pkd->param = param;
282 pkd->key = alloc_string(key);
283 pkd->info = info;
285 return pkd;
288 void add_function_param_key_hook(const char *look_for, param_key_hook *call_back,
289 int param, const char *key, void *info)
291 struct param_key_data *pkd;
293 pkd = alloc_pkd(call_back, param, key, info);
294 add_function_hook(look_for, &param_key_function, pkd);
297 void add_function_param_key_hook_late(const char *look_for, param_key_hook *call_back,
298 int param, const char *key, void *info)
300 struct param_key_data *pkd;
302 pkd = alloc_pkd(call_back, param, key, info);
303 add_function_hook_late(look_for, &param_key_function, pkd);
306 void return_implies_param_key(const char *look_for, sval_t start, sval_t end,
307 param_key_hook *call_back,
308 int param, const char *key, void *info)
310 struct param_key_data *pkd;
312 pkd = alloc_pkd(call_back, param, key, info);
313 return_implies_state_sval(look_for, start, end, &param_key_implies_function, pkd);
316 void return_implies_param_key_exact(const char *look_for, sval_t start, sval_t end,
317 param_key_hook *call_back,
318 int param, const char *key, void *info)
320 struct param_key_data *pkd;
322 pkd = alloc_pkd(call_back, param, key, info);
323 return_implies_exact(look_for, start, end, &param_key_implies_function, pkd);
326 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
327 void *info)
329 struct fcall_back *cb;
331 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
332 add_callback(func_hash, look_for, cb);
335 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
336 void *info)
338 struct fcall_back *cb;
340 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
341 add_callback(func_hash, look_for, cb);
344 void return_implies_state(const char *look_for, long long start, long long end,
345 implication_hook *call_back, void *info)
347 struct fcall_back *cb;
349 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
350 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
351 add_callback(func_hash, look_for, cb);
354 void return_implies_state_sval(const char *look_for, sval_t start, sval_t end,
355 implication_hook *call_back, void *info)
357 struct fcall_back *cb;
359 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
360 cb->range = alloc_range_perm(start, end);
361 add_callback(func_hash, look_for, cb);
364 void return_implies_exact(const char *look_for, sval_t start, sval_t end,
365 implication_hook *call_back, void *info)
367 struct fcall_back *cb;
369 cb = alloc_fcall_back(RANGED_EXACT, call_back, info);
370 cb->range = alloc_range_perm(start, end);
371 add_callback(func_hash, look_for, cb);
374 static struct return_implies_callback *alloc_db_return_callback(int type, bool param_key, void *callback)
376 struct return_implies_callback *cb;
378 cb = __alloc_return_implies_callback(0);
379 cb->type = type;
380 cb->param_key = param_key;
381 cb->callback = callback;
383 return cb;
386 void select_return_states_hook(int type, return_implies_hook *callback)
388 struct return_implies_callback *cb;
390 cb = alloc_db_return_callback(type, false, callback);
391 add_ptr_list(&db_return_states_list, cb);
394 static void call_db_return_callback(struct db_callback_info *db_info,
395 struct return_implies_callback *cb,
396 int param, char *key, char *value)
398 if (cb->param_key) {
399 // FIXME check if cb->pk_callback was already called
400 db_helper(db_info->expr, cb->pk_callback, param, key, NULL);
401 } else {
402 cb->callback(db_info->expr, param, key, value);
406 void select_return_param_key(int type, param_key_hook *callback)
408 struct return_implies_callback *cb;
410 cb = alloc_db_return_callback(type, true, callback);
411 add_ptr_list(&db_return_states_list, cb);
414 void select_return_states_before(void_fn *fn)
416 void_fn **p = malloc(sizeof(void_fn *));
417 *p = fn;
418 add_ptr_list(&return_states_before, p);
421 void select_return_states_after(void_fn *fn)
423 void_fn **p = malloc(sizeof(void_fn *));
424 *p = fn;
425 add_ptr_list(&return_states_after, p);
428 static void call_return_states_before_hooks(void)
430 void_fn **fn;
432 FOR_EACH_PTR(return_states_before, fn) {
433 (*fn)();
434 } END_FOR_EACH_PTR(fn);
437 static int call_call_backs(struct call_back_list *list, int type,
438 const char *fn, struct expression *expr)
440 struct fcall_back *tmp;
441 int handled = 0;
443 FOR_EACH_PTR(list, tmp) {
444 if (tmp->type == type) {
445 (tmp->u.call_back)(fn, expr, tmp->info);
446 handled = 1;
448 } END_FOR_EACH_PTR(tmp);
450 return handled;
453 static void call_function_hooks(struct expression *expr, enum fn_hook_type type)
455 struct call_back_list *call_backs;
456 struct expression *fn;
458 while (expr->type == EXPR_ASSIGNMENT)
459 expr = strip_expr(expr->right);
460 if (expr->type != EXPR_CALL)
461 return;
463 fn = strip_expr(expr->fn);
464 if (fn->type != EXPR_SYMBOL || !fn->symbol)
465 return;
467 call_backs = search_callback(func_hash, (char *)fn->symbol->ident->name);
468 if (!call_backs)
469 return;
471 call_call_backs(call_backs, type, fn->symbol->ident->name, expr);
474 static void call_return_states_after_hooks(struct expression *expr)
476 void_fn **fn;
478 FOR_EACH_PTR(return_states_after, fn) {
479 (*fn)();
480 } END_FOR_EACH_PTR(fn);
481 __pass_to_client(expr, FUNCTION_CALL_HOOK_AFTER_DB);
482 call_function_hooks(expr, REGULAR_CALL_LATE);
485 static void call_ranged_call_backs(struct call_back_list *list,
486 const char *fn, struct expression *call_expr,
487 struct expression *assign_expr)
489 struct fcall_back *tmp;
491 FOR_EACH_PTR(list, tmp) {
492 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
493 } END_FOR_EACH_PTR(tmp);
496 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
497 struct data_range *drange)
499 struct call_back_list *ret = NULL;
500 struct fcall_back *tmp;
502 FOR_EACH_PTR(list, tmp) {
503 if (tmp->type != RANGED_CALL &&
504 tmp->type != RANGED_EXACT)
505 continue;
506 if (ranges_equiv(tmp->range, drange))
507 add_ptr_list(&ret, tmp);
508 } END_FOR_EACH_PTR(tmp);
509 return ret;
512 static int in_list_exact_sval(struct range_list *list, struct data_range *drange)
514 struct data_range *tmp;
516 FOR_EACH_PTR(list, tmp) {
517 if (ranges_equiv(tmp, drange))
518 return 1;
519 } END_FOR_EACH_PTR(tmp);
520 return 0;
523 static int assign_ranged_funcs(const char *fn, struct expression *expr,
524 struct call_back_list *call_backs)
526 struct fcall_back *tmp;
527 struct sm_state *sm;
528 char *var_name;
529 struct symbol *sym;
530 struct smatch_state *estate;
531 struct stree *tmp_stree;
532 struct stree *final_states = NULL;
533 struct range_list *handled_ranges = NULL;
534 struct call_back_list *same_range_call_backs = NULL;
535 struct range_list *rl;
536 int handled = 0;
538 if (!call_backs)
539 return 0;
541 var_name = expr_to_var_sym(expr->left, &sym);
542 if (!var_name || !sym)
543 goto free;
545 FOR_EACH_PTR(call_backs, tmp) {
546 if (tmp->type != RANGED_CALL &&
547 tmp->type != RANGED_EXACT)
548 continue;
550 if (in_list_exact_sval(handled_ranges, tmp->range))
551 continue;
552 __push_fake_cur_stree();
553 tack_on(&handled_ranges, tmp->range);
555 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
556 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
557 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
559 rl = alloc_rl(tmp->range->min, tmp->range->max);
560 rl = cast_rl(get_type(expr->left), rl);
561 estate = alloc_estate_rl(rl);
562 set_extra_mod(var_name, sym, expr->left, estate);
564 tmp_stree = __pop_fake_cur_stree();
565 merge_fake_stree(&final_states, tmp_stree);
566 free_stree(&tmp_stree);
567 handled = 1;
568 } END_FOR_EACH_PTR(tmp);
570 FOR_EACH_SM(final_states, sm) {
571 __set_sm(sm);
572 } END_FOR_EACH_SM(sm);
574 free_stree(&final_states);
575 free:
576 free_string(var_name);
577 return handled;
580 static void call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left, struct stree **implied_true, struct stree **implied_false)
582 struct call_back_list *call_backs;
583 struct fcall_back *tmp;
584 const char *fn;
585 struct data_range *value_range;
586 struct stree *true_states = NULL;
587 struct stree *false_states = NULL;
588 struct stree *tmp_stree;
590 *implied_true = NULL;
591 *implied_false = NULL;
592 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
593 return;
594 fn = expr->fn->symbol->ident->name;
595 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
596 if (!call_backs)
597 return;
598 value_range = alloc_range(sval, sval);
600 /* set true states */
601 __push_fake_cur_stree();
602 FOR_EACH_PTR(call_backs, tmp) {
603 if (tmp->type != RANGED_CALL &&
604 tmp->type != RANGED_EXACT)
605 continue;
606 if (!true_comparison_range_LR(comparison, tmp->range, value_range, left))
607 continue;
608 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
609 } END_FOR_EACH_PTR(tmp);
610 tmp_stree = __pop_fake_cur_stree();
611 merge_fake_stree(&true_states, tmp_stree);
612 free_stree(&tmp_stree);
614 /* set false states */
615 __push_fake_cur_stree();
616 FOR_EACH_PTR(call_backs, tmp) {
617 if (tmp->type != RANGED_CALL &&
618 tmp->type != RANGED_EXACT)
619 continue;
620 if (!false_comparison_range_LR(comparison, tmp->range, value_range, left))
621 continue;
622 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
623 } END_FOR_EACH_PTR(tmp);
624 tmp_stree = __pop_fake_cur_stree();
625 merge_fake_stree(&false_states, tmp_stree);
626 free_stree(&tmp_stree);
628 *implied_true = true_states;
629 *implied_false = false_states;
632 static void set_implied_states(struct db_callback_info *db_info)
634 struct sm_state *sm;
636 FOR_EACH_SM(db_info->implied, sm) {
637 __set_sm(sm);
638 } END_FOR_EACH_SM(sm);
640 free_stree(&db_info->implied);
643 static void store_return_state(struct db_callback_info *db_info, const char *ret_str, struct smatch_state *state)
645 db_info->ret_str = alloc_sname(ret_str),
646 db_info->ret_state = state;
649 static bool fake_a_param_assignment(struct expression *expr, const char *ret_str, struct smatch_state *orig)
651 struct expression *arg, *left, *right, *tmp, *fake_assign;
652 char *p;
653 int param;
654 char buf[256];
655 char *str;
657 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
658 return false;
659 left = expr->left;
660 right = expr->right;
662 while (right->type == EXPR_ASSIGNMENT)
663 right = strip_expr(right->right);
664 if (!right || right->type != EXPR_CALL)
665 return false;
667 p = strchr(ret_str, '[');
668 if (!p)
669 return false;
671 p++;
672 if (p[0] == '=' && p[1] == '=')
673 p += 2;
674 if (p[0] != '$')
675 return false;
677 snprintf(buf, sizeof(buf), "%s", p);
679 p = buf;
680 p += 1;
681 param = strtol(p, &p, 10);
683 p = strchr(p, ']');
684 if (!p || *p != ']')
685 return false;
686 *p = '\0';
688 arg = get_argument_from_call_expr(right->args, param);
689 if (!arg)
690 return false;
692 /* There should be a get_other_name() function which returns an expr */
693 tmp = get_assigned_expr(arg);
694 if (tmp)
695 arg = tmp;
698 * This is a sanity check to prevent side effects from evaluating stuff
699 * twice.
701 str = expr_to_chunk_sym_vsl(arg, NULL, NULL);
702 if (!str)
703 return false;
704 free_string(str);
706 right = gen_expression_from_key(arg, buf);
707 if (!right) /* Mostly fails for binops like [$0 + 4032] */
708 return false;
709 fake_assign = assign_expression(left, '=', right);
710 __in_fake_parameter_assign++;
711 __split_expr(fake_assign);
712 __in_fake_parameter_assign--;
715 * If the return is "0-65531[$0->nla_len - 4]" the faked expression
716 * is maybe (-4)-65531 but we know it is in the 0-65531 range so both
717 * parts have to be considered. We use _nomod() because it's not really
718 * another modification, it's just a clarification.
721 if (estate_rl(orig)) {
722 struct smatch_state *faked;
723 struct range_list *rl;
725 faked = get_extra_state(left);
726 if (estate_rl(faked)) {
727 rl = rl_intersection(estate_rl(faked), estate_rl(orig));
728 if (rl)
729 set_extra_expr_nomod(expr, alloc_estate_rl(rl));
733 return true;
736 static void fake_return_assignment(struct db_callback_info *db_info, int type, int param, char *key, char *value)
738 struct expression *call, *left, *right, *assign;
739 int right_param;
741 if (type != PARAM_COMPARE)
742 return;
744 call = db_info->expr;
745 while (call && call->type == EXPR_ASSIGNMENT)
746 call = strip_expr(call->right);
747 if (!call || call->type != EXPR_CALL)
748 return;
750 // TODO: This only handles "$->foo = arg" and not "$->foo = arg->bar".
751 if (param != -1)
752 return;
753 if (!value || strncmp(value, "== $", 4) != 0)
754 return;
755 if (!isdigit(value[4]) || value[5] != '\0')
756 return;
757 right_param = atoi(value + 4);
759 left = gen_expr_from_param_key(db_info->expr, param, key);
760 if (!left)
761 return;
762 right = get_argument_from_call_expr(call->args, right_param);
764 assign = assign_expression(left, '=', right);
765 push_expression(&db_info->fake_param_assign_stack, assign);
768 static void set_fresh_mtag_returns(struct db_callback_info *db_info)
770 struct expression *expr = db_info->expr->left;
771 struct smatch_state *state;
773 if (!db_info->ret_state)
774 return;
776 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
777 state = get_mtag_return(db_info->expr, state);
778 if (!state)
779 return;
781 set_real_absolute(expr, state);
782 set_extra_expr_mod(expr, state);
784 db_info->ret_state = NULL;
785 db_info->ret_str = NULL;
788 static void set_return_assign_state(struct db_callback_info *db_info)
790 struct expression *expr = db_info->expr->left;
791 struct expression *fake_assign;
792 struct smatch_state *state;
794 if (!db_info->ret_state)
795 return;
797 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
798 if (!fake_a_param_assignment(db_info->expr, db_info->ret_str, state))
799 set_extra_expr_mod(expr, state);
801 while ((fake_assign = pop_expression(&db_info->fake_param_assign_stack))) {
802 struct range_list *left, *right;
805 * Originally, I tried to do this as a assignment to record that
806 * a = frob(b) implies that "a->foo == b->foo" etc. But that
807 * caused a problem because then it was recorded that "a->foo"
808 * was modified and recorded as a PARAM_SET in the database.
810 * So now, instead of faking an assignment we use
811 * set_extra_expr_nomod() but it's still recorded as an
812 * assignment in the ->fake_param_assign_stack for legacy
813 * reasons and because it's a handy way to store a left/right
814 * pair.
817 get_absolute_rl(fake_assign->left, &left);
818 get_absolute_rl(fake_assign->right, &right);
819 right = cast_rl(get_type(fake_assign->left), right);
820 // FIXME: add some sanity checks
821 // FIXME: preserve the sm state if possible
822 set_extra_expr_nomod(fake_assign->left, alloc_estate_rl(right));
825 db_info->ret_state = NULL;
826 db_info->ret_str = NULL;
829 static void set_other_side_state(struct db_callback_info *db_info)
831 struct expression *expr = db_info->var_expr;
832 struct smatch_state *state;
834 if (!db_info->ret_state)
835 return;
837 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
838 set_extra_expr_nomod(expr, state);
839 db_info->ret_state = NULL;
840 db_info->ret_str = NULL;
843 static void handle_ret_equals_param(char *ret_string, struct range_list *rl, struct expression *call)
845 char *str;
846 long long param;
847 struct expression *arg;
848 struct range_list *orig;
850 str = strstr(ret_string, "==$");
851 if (!str)
852 return;
853 str += 3;
854 param = strtoll(str, NULL, 10);
855 arg = get_argument_from_call_expr(call->args, param);
856 if (!arg)
857 return;
858 get_absolute_rl(arg, &orig);
859 rl = rl_intersection(orig, rl);
860 if (!rl)
861 return;
862 set_extra_expr_nomod(arg, alloc_estate_rl(rl));
865 static int impossible_limit(struct db_callback_info *db_info, int param, char *key, char *value)
867 struct expression *expr = db_info->expr;
868 struct expression *arg;
869 struct smatch_state *state;
870 struct range_list *passed;
871 struct range_list *limit;
872 struct symbol *compare_type;
874 while (expr->type == EXPR_ASSIGNMENT)
875 expr = strip_expr(expr->right);
876 if (expr->type != EXPR_CALL)
877 return 0;
879 arg = get_argument_from_call_expr(expr->args, param);
880 if (!arg)
881 return 0;
883 if (strcmp(key, "$") == 0) {
884 if (!get_implied_rl(arg, &passed))
885 return 0;
887 compare_type = get_arg_type(expr->fn, param);
888 } else {
889 char *name;
890 struct symbol *sym;
892 name = get_variable_from_key(arg, key, &sym);
893 if (!name || !sym)
894 return 0;
896 state = get_state(SMATCH_EXTRA, name, sym);
897 if (!state) {
898 free_string(name);
899 return 0;
901 passed = estate_rl(state);
902 if (!passed || is_whole_rl(passed)) {
903 free_string(name);
904 return 0;
907 compare_type = get_member_type_from_key(arg, key);
910 passed = cast_rl(compare_type, passed);
911 call_results_to_rl(expr, compare_type, value, &limit);
912 if (!limit || is_whole_rl(limit))
913 return 0;
914 if (possibly_true_rl(passed, SPECIAL_EQUAL, limit))
915 return 0;
916 if (option_debug || local_debug)
917 sm_msg("impossible: %d '%s' limit '%s' == '%s' return='%s'", param, key, show_rl(passed), value, db_info->ret_str);
918 return 1;
921 static int is_impossible_data(int type, struct db_callback_info *db_info, int param, char *key, char *value)
923 if (type == PARAM_LIMIT && impossible_limit(db_info, param, key, value))
924 return 1;
925 if (type == COMPARE_LIMIT && param_compare_limit_is_impossible(db_info->expr, param, key, value)) {
926 if (local_debug)
927 sm_msg("param_compare_limit_is_impossible: %d %s %s", param, key, value);
928 return 1;
930 return 0;
933 static int func_type_mismatch(struct expression *expr, const char *value)
935 struct symbol *type;
937 /* This makes faking returns easier */
938 if (!value || value[0] == '\0')
939 return 0;
941 while (expr->type == EXPR_ASSIGNMENT)
942 expr = strip_expr(expr->right);
945 * Short cut: We only care about function pointers that are struct
946 * members.
949 if (expr->fn->type == EXPR_SYMBOL)
950 return 0;
952 type = get_type(expr->fn);
953 if (!type)
954 return 0;
955 if (type->type == SYM_PTR)
956 type = get_real_base_type(type);
958 if (strcmp(type_to_str(type), value) == 0)
959 return 0;
961 return 1;
964 static int db_compare_callback(void *_info, int argc, char **argv, char **azColName)
966 struct db_callback_info *db_info = _info;
967 struct range_list *var_rl = db_info->rl;
968 struct range_list *ret_range;
969 int type, param;
970 char *ret_str, *key, *value;
971 struct return_implies_callback *tmp;
972 struct stree *stree;
973 int return_id;
974 int comparison;
976 if (argc != 6)
977 return 0;
979 return_id = atoi(argv[0]);
980 ret_str = argv[1];
981 type = atoi(argv[2]);
982 param = atoi(argv[3]);
983 key = argv[4];
984 value = argv[5];
986 db_info->has_states = 1;
987 if (db_info->prev_return_id != -1 && type == INTERNAL) {
988 set_other_side_state(db_info);
989 set_implied_states(db_info);
990 stree = __pop_fake_cur_stree();
991 if (!db_info->cull)
992 merge_fake_stree(&db_info->stree, stree);
993 free_stree(&stree);
994 __push_fake_cur_stree();
995 db_info->cull = 0;
997 db_info->prev_return_id = return_id;
999 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1000 db_info->cull = 1;
1001 if (db_info->cull)
1002 return 0;
1003 if (type == CULL_PATH) {
1004 db_info->cull = 1;
1005 return 0;
1008 if (is_impossible_data(type, db_info, param, key, value)) {
1009 db_info->cull = 1;
1010 return 0;
1013 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1014 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1015 if (!ret_range)
1016 ret_range = alloc_whole_rl(get_type(db_info->expr));
1018 comparison = db_info->comparison;
1019 if (db_info->left)
1020 comparison = flip_comparison(comparison);
1022 if (db_info->true_side) {
1023 if (!possibly_true_rl(var_rl, comparison, ret_range))
1024 return 0;
1025 if (type == PARAM_LIMIT)
1026 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1027 else if (type > PARAM_LIMIT)
1028 set_implied_states(db_info);
1029 filter_by_comparison(&var_rl, comparison, ret_range);
1030 filter_by_comparison(&ret_range, flip_comparison(comparison), var_rl);
1031 } else {
1032 if (!possibly_false_rl(var_rl, comparison, ret_range))
1033 return 0;
1034 if (type == PARAM_LIMIT)
1035 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1036 else if (type > PARAM_LIMIT)
1037 set_implied_states(db_info);
1038 filter_by_comparison(&var_rl, negate_comparison(comparison), ret_range);
1039 filter_by_comparison(&ret_range, flip_comparison(negate_comparison(comparison)), var_rl);
1042 handle_ret_equals_param(ret_str, ret_range, db_info->expr);
1044 if (type == INTERNAL) {
1045 set_state(-1, "unnull_path", NULL, &true_state);
1046 __add_return_comparison(strip_expr(db_info->expr), ret_str);
1047 __add_return_to_param_mapping(db_info->expr, ret_str);
1048 store_return_state(db_info, ret_str, alloc_estate_rl(clone_rl(var_rl)));
1051 FOR_EACH_PTR(db_info->callbacks, tmp) {
1052 if (tmp->type == type)
1053 call_db_return_callback(db_info, tmp, param, key, value);
1054 } END_FOR_EACH_PTR(tmp);
1056 fake_return_assignment(db_info, type, param, key, value);
1058 return 0;
1061 static void compare_db_return_states_callbacks(struct expression *left, int comparison, struct expression *right, struct stree *implied_true, struct stree *implied_false)
1063 struct stree *orig_states;
1064 struct stree *stree;
1065 struct stree *true_states;
1066 struct stree *false_states;
1067 struct sm_state *sm;
1068 struct db_callback_info db_info = {};
1069 struct expression *var_expr;
1070 struct expression *call_expr;
1071 struct range_list *rl;
1072 int call_on_left;
1074 orig_states = clone_stree(__get_cur_stree());
1076 /* legacy cruft. need to fix call_implies_callbacks(). */
1077 call_on_left = 1;
1078 call_expr = left;
1079 var_expr = right;
1080 if (left->type != EXPR_CALL) {
1081 call_on_left = 0;
1082 call_expr = right;
1083 var_expr = left;
1086 get_absolute_rl(var_expr, &rl);
1088 db_info.comparison = comparison;
1089 db_info.expr = call_expr;
1090 db_info.rl = rl;
1091 db_info.left = call_on_left;
1092 db_info.callbacks = db_return_states_list;
1093 db_info.var_expr = var_expr;
1095 call_return_states_before_hooks();
1097 db_info.true_side = 1;
1098 db_info.stree = NULL;
1099 db_info.prev_return_id = -1;
1100 __push_fake_cur_stree();
1101 sql_select_return_states("return_id, return, type, parameter, key, value",
1102 call_expr, db_compare_callback, &db_info);
1103 set_other_side_state(&db_info);
1104 set_implied_states(&db_info);
1105 stree = __pop_fake_cur_stree();
1106 if (!db_info.cull)
1107 merge_fake_stree(&db_info.stree, stree);
1108 free_stree(&stree);
1109 true_states = db_info.stree;
1110 if (!true_states && db_info.has_states) {
1111 __push_fake_cur_stree();
1112 set_path_impossible();
1113 true_states = __pop_fake_cur_stree();
1116 nullify_path();
1117 __unnullify_path();
1118 FOR_EACH_SM(orig_states, sm) {
1119 __set_sm_cur_stree(sm);
1120 } END_FOR_EACH_SM(sm);
1122 db_info.true_side = 0;
1123 db_info.stree = NULL;
1124 db_info.prev_return_id = -1;
1125 db_info.cull = 0;
1126 __push_fake_cur_stree();
1127 sql_select_return_states("return_id, return, type, parameter, key, value", call_expr,
1128 db_compare_callback, &db_info);
1129 set_other_side_state(&db_info);
1130 set_implied_states(&db_info);
1131 stree = __pop_fake_cur_stree();
1132 if (!db_info.cull)
1133 merge_fake_stree(&db_info.stree, stree);
1134 free_stree(&stree);
1135 false_states = db_info.stree;
1136 if (!false_states && db_info.has_states) {
1137 __push_fake_cur_stree();
1138 set_path_impossible();
1139 false_states = __pop_fake_cur_stree();
1142 nullify_path();
1143 __unnullify_path();
1144 FOR_EACH_SM(orig_states, sm) {
1145 __set_sm_cur_stree(sm);
1146 } END_FOR_EACH_SM(sm);
1148 free_stree(&orig_states);
1150 FOR_EACH_SM(true_states, sm) {
1151 __set_true_false_sm(sm, NULL);
1152 } END_FOR_EACH_SM(sm);
1153 FOR_EACH_SM(false_states, sm) {
1154 __set_true_false_sm(NULL, sm);
1155 } END_FOR_EACH_SM(sm);
1157 free_stree(&true_states);
1158 free_stree(&false_states);
1160 call_return_states_after_hooks(call_expr);
1162 FOR_EACH_SM(implied_true, sm) {
1163 __set_true_false_sm(sm, NULL);
1164 } END_FOR_EACH_SM(sm);
1165 FOR_EACH_SM(implied_false, sm) {
1166 __set_true_false_sm(NULL, sm);
1167 } END_FOR_EACH_SM(sm);
1170 void function_comparison(struct expression *left, int comparison, struct expression *right)
1172 struct expression *var_expr;
1173 struct expression *call_expr;
1174 struct stree *implied_true = NULL;
1175 struct stree *implied_false = NULL;
1176 struct range_list *rl;
1177 sval_t sval;
1178 int call_on_left;
1180 if (unreachable())
1181 return;
1183 /* legacy cruft. need to fix call_implies_callbacks(). */
1184 call_on_left = 1;
1185 call_expr = left;
1186 var_expr = right;
1187 if (left->type != EXPR_CALL) {
1188 call_on_left = 0;
1189 call_expr = right;
1190 var_expr = left;
1193 get_absolute_rl(var_expr, &rl);
1195 if (rl_to_sval(rl, &sval))
1196 call_implies_callbacks(comparison, call_expr, sval, call_on_left, &implied_true, &implied_false);
1198 compare_db_return_states_callbacks(left, comparison, right, implied_true, implied_false);
1199 free_stree(&implied_true);
1200 free_stree(&implied_false);
1203 static void call_ranged_return_hooks(struct db_callback_info *db_info)
1205 struct call_back_list *call_backs;
1206 struct range_list *range_rl;
1207 struct expression *expr;
1208 struct fcall_back *tmp;
1209 char *fn;
1211 expr = strip_expr(db_info->expr);
1212 while (expr->type == EXPR_ASSIGNMENT)
1213 expr = strip_expr(expr->right);
1214 if (expr->type != EXPR_CALL ||
1215 expr->fn->type != EXPR_SYMBOL)
1216 return;
1218 fn = expr->fn->symbol_name->name;
1220 call_backs = search_callback(func_hash, fn);
1221 FOR_EACH_PTR(call_backs, tmp) {
1222 if (tmp->type != RANGED_CALL)
1223 continue;
1224 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1225 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1226 if (possibly_true_rl(range_rl, SPECIAL_EQUAL, estate_rl(db_info->ret_state)))
1227 (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
1228 } END_FOR_EACH_PTR(tmp);
1230 FOR_EACH_PTR(call_backs, tmp) {
1231 if (tmp->type != RANGED_EXACT)
1232 continue;
1233 if (!estate_rl(db_info->ret_state))
1234 continue;
1236 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1237 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1240 * If there is an returned value out of range then this is not
1241 * an exact match. In other words, "0,4096-ptr_max" is not
1242 * necessarily a valid match.
1245 if (remove_range(estate_rl(db_info->ret_state),
1246 rl_min(range_rl), rl_max(range_rl)))
1247 continue;
1248 (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
1249 } END_FOR_EACH_PTR(tmp);
1252 static int db_assign_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1254 struct db_callback_info *db_info = _info;
1255 struct range_list *ret_range;
1256 int type, param;
1257 char *ret_str, *key, *value;
1258 struct return_implies_callback *tmp;
1259 struct stree *stree;
1260 int return_id;
1262 if (argc != 6)
1263 return 0;
1265 return_id = atoi(argv[0]);
1266 ret_str = argv[1];
1267 type = atoi(argv[2]);
1268 param = atoi(argv[3]);
1269 key = argv[4];
1270 value = argv[5];
1272 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1273 call_ranged_return_hooks(db_info);
1274 set_return_assign_state(db_info);
1275 set_implied_states(db_info);
1276 stree = __pop_fake_cur_stree();
1277 if (!db_info->cull)
1278 merge_fake_stree(&db_info->stree, stree);
1279 free_stree(&stree);
1280 __push_fake_cur_stree();
1281 db_info->cull = 0;
1283 db_info->prev_return_id = return_id;
1285 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1286 db_info->cull = 1;
1287 if (db_info->cull)
1288 return 0;
1289 if (type == CULL_PATH) {
1290 db_info->cull = 1;
1291 return 0;
1293 if (is_impossible_data(type, db_info, param, key, value)) {
1294 db_info->cull = 1;
1295 return 0;
1298 if (type == PARAM_LIMIT)
1299 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1300 else if (type > PARAM_LIMIT)
1301 set_implied_states(db_info);
1303 db_info->handled = 1;
1304 call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), ret_str, &ret_range);
1305 if (!ret_range)
1306 ret_range = alloc_whole_rl(get_type(strip_expr(db_info->expr->right)));
1307 ret_range = cast_rl(get_type(db_info->expr->right), ret_range);
1309 if (type == INTERNAL) {
1310 set_state(-1, "unnull_path", NULL, &true_state);
1311 __add_return_comparison(strip_expr(db_info->expr->right), ret_str);
1312 __add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), ret_str);
1313 __add_return_to_param_mapping(db_info->expr, ret_str);
1314 store_return_state(db_info, ret_str, alloc_estate_rl(ret_range));
1315 set_fresh_mtag_returns(db_info);
1318 FOR_EACH_PTR(db_return_states_list, tmp) {
1319 if (tmp->type == type)
1320 call_db_return_callback(db_info, tmp, param, key, value);
1321 } END_FOR_EACH_PTR(tmp);
1323 fake_return_assignment(db_info, type, param, key, value);
1325 return 0;
1328 static int db_return_states_assign(struct expression *expr)
1330 struct expression *right;
1331 struct sm_state *sm;
1332 struct stree *stree;
1333 struct db_callback_info db_info = {};
1335 right = strip_expr(expr->right);
1337 db_info.prev_return_id = -1;
1338 db_info.expr = expr;
1339 db_info.stree = NULL;
1340 db_info.handled = 0;
1342 call_return_states_before_hooks();
1344 __push_fake_cur_stree();
1345 sql_select_return_states("return_id, return, type, parameter, key, value",
1346 right, db_assign_return_states_callback, &db_info);
1347 if (option_debug) {
1348 sm_msg("%s return_id %d return_ranges %s",
1349 db_info.cull ? "culled" : "merging",
1350 db_info.prev_return_id,
1351 db_info.ret_state ? db_info.ret_state->name : "'<empty>'");
1353 if (db_info.handled)
1354 call_ranged_return_hooks(&db_info);
1355 set_return_assign_state(&db_info);
1356 set_implied_states(&db_info);
1357 stree = __pop_fake_cur_stree();
1358 if (!db_info.cull)
1359 merge_fake_stree(&db_info.stree, stree);
1360 free_stree(&stree);
1362 if (!db_info.stree && db_info.cull) { /* this means we culled everything */
1363 set_extra_expr_mod(expr->left, alloc_estate_whole(get_type(expr->left)));
1364 set_path_impossible();
1366 FOR_EACH_SM(db_info.stree, sm) {
1367 __set_sm(sm);
1368 } END_FOR_EACH_SM(sm);
1370 free_stree(&db_info.stree);
1371 call_return_states_after_hooks(right);
1373 return db_info.handled;
1376 static int handle_implied_return(struct expression *expr)
1378 struct range_list *rl;
1380 if (!get_implied_return(expr->right, &rl))
1381 return 0;
1382 rl = cast_rl(get_type(expr->left), rl);
1383 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1384 return 1;
1387 static void match_assign_call(struct expression *expr)
1389 struct call_back_list *call_backs;
1390 const char *fn;
1391 struct expression *right;
1392 int handled = 0;
1393 struct range_list *rl;
1395 if (expr->op != '=')
1396 return;
1398 right = strip_expr(expr->right);
1399 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
1400 handled |= db_return_states_assign(expr);
1401 if (!handled)
1402 goto assigned_unknown;
1403 return;
1405 if (is_fake_call(right))
1406 return;
1408 fn = right->fn->symbol->ident->name;
1409 call_backs = search_callback(func_hash, (char *)fn);
1412 * The ordering here is sort of important.
1413 * One example, of how this matters is that when we do:
1415 * len = strlen(str);
1417 * That is handled by smatch_common_functions.c and smatch_strlen.c.
1418 * They use implied_return and function_assign_hook respectively.
1419 * We want to get the implied return first before we do the function
1420 * assignment hook otherwise we end up writing the wrong thing for len
1421 * in smatch_extra.c because we assume that it already holds the
1422 * strlen() when we haven't set it yet.
1425 if (db_return_states_assign(expr))
1426 handled = 1;
1427 else
1428 handled = assign_ranged_funcs(fn, expr, call_backs);
1429 handled |= handle_implied_return(expr);
1432 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
1434 if (handled)
1435 return;
1437 assigned_unknown:
1438 get_absolute_rl(expr->right, &rl);
1439 rl = cast_rl(get_type(expr->left), rl);
1440 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1443 static int db_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1445 struct db_callback_info *db_info = _info;
1446 struct range_list *ret_range;
1447 int type, param;
1448 char *ret_str, *key, *value;
1449 struct return_implies_callback *tmp;
1450 struct stree *stree;
1451 int return_id;
1452 char buf[64];
1454 if (argc != 6)
1455 return 0;
1457 return_id = atoi(argv[0]);
1458 ret_str = argv[1];
1459 type = atoi(argv[2]);
1460 param = atoi(argv[3]);
1461 key = argv[4];
1462 value = argv[5];
1464 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1465 call_ranged_return_hooks(db_info);
1466 set_implied_states(db_info);
1467 stree = __pop_fake_cur_stree();
1468 if (!db_info->cull)
1469 merge_fake_stree(&db_info->stree, stree);
1470 free_stree(&stree);
1471 __push_fake_cur_stree();
1472 __unnullify_path();
1473 db_info->cull = 0;
1475 db_info->prev_return_id = return_id;
1477 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1478 db_info->cull = 1;
1479 if (db_info->cull)
1480 return 0;
1481 if (type == CULL_PATH) {
1482 db_info->cull = 1;
1483 return 0;
1485 if (is_impossible_data(type, db_info, param, key, value)) {
1486 db_info->cull = 1;
1487 return 0;
1490 if (type == PARAM_LIMIT)
1491 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1492 else if (type > PARAM_LIMIT)
1493 set_implied_states(db_info);
1495 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1496 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1498 if (type == INTERNAL) {
1499 struct smatch_state *state;
1501 set_state(-1, "unnull_path", NULL, &true_state);
1502 __add_return_comparison(strip_expr(db_info->expr), ret_str);
1503 __add_return_to_param_mapping(db_info->expr, ret_str);
1505 * We want to store the return values so that we can split the strees
1506 * in smatch_db.c. This uses set_state() directly because it's not a
1507 * real smatch_extra state.
1509 snprintf(buf, sizeof(buf), "return %p", db_info->expr);
1510 state = alloc_estate_rl(ret_range);
1511 set_state(SMATCH_EXTRA, buf, NULL, state);
1512 store_return_state(db_info, ret_str, state);
1515 FOR_EACH_PTR(db_return_states_list, tmp) {
1516 if (tmp->type == type)
1517 call_db_return_callback(db_info, tmp, param, key, value);
1518 } END_FOR_EACH_PTR(tmp);
1520 fake_return_assignment(db_info, type, param, key, value);
1522 return 0;
1525 static void db_return_states(struct expression *expr)
1527 struct sm_state *sm;
1528 struct stree *stree;
1529 struct db_callback_info db_info = {};
1531 if (!__get_cur_stree()) /* no return functions */
1532 return;
1534 db_info.prev_return_id = -1;
1535 db_info.expr = expr;
1536 db_info.stree = NULL;
1538 call_return_states_before_hooks();
1540 __push_fake_cur_stree();
1541 __unnullify_path();
1542 sql_select_return_states("return_id, return, type, parameter, key, value",
1543 expr, db_return_states_callback, &db_info);
1544 call_ranged_return_hooks(&db_info);
1545 set_implied_states(&db_info);
1546 stree = __pop_fake_cur_stree();
1547 if (!db_info.cull)
1548 merge_fake_stree(&db_info.stree, stree);
1549 free_stree(&stree);
1551 FOR_EACH_SM(db_info.stree, sm) {
1552 __set_sm(sm);
1553 } END_FOR_EACH_SM(sm);
1555 free_stree(&db_info.stree);
1556 call_return_states_after_hooks(expr);
1559 static int is_condition_call(struct expression *expr)
1561 struct expression *tmp;
1563 FOR_EACH_PTR_REVERSE(big_condition_stack, tmp) {
1564 if (expr == tmp || expr_get_parent_expr(expr) == tmp)
1565 return 1;
1566 if (tmp->pos.line < expr->pos.line)
1567 return 0;
1568 } END_FOR_EACH_PTR_REVERSE(tmp);
1570 return 0;
1573 static void db_return_states_call(struct expression *expr)
1575 if (unreachable())
1576 return;
1578 if (is_assigned_call(expr) || is_fake_assigned_call(expr))
1579 return;
1580 if (is_condition_call(expr))
1581 return;
1582 db_return_states(expr);
1585 static void match_function_call(struct expression *expr)
1587 call_function_hooks(expr, REGULAR_CALL);
1588 db_return_states_call(expr);
1591 static void match_macro_assign(struct expression *expr)
1593 struct call_back_list *call_backs;
1594 const char *macro;
1595 struct expression *right;
1597 right = strip_expr(expr->right);
1598 macro = get_macro_name(right->pos);
1599 call_backs = search_callback(func_hash, (char *)macro);
1600 if (!call_backs)
1601 return;
1602 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
1603 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
1606 int get_implied_return(struct expression *expr, struct range_list **rl)
1608 struct call_back_list *call_backs;
1609 struct fcall_back *tmp;
1610 int handled = 0;
1611 char *fn;
1613 *rl = NULL;
1615 expr = strip_expr(expr);
1616 fn = expr_to_var(expr->fn);
1617 if (!fn)
1618 goto out;
1620 call_backs = search_callback(func_hash, fn);
1622 FOR_EACH_PTR(call_backs, tmp) {
1623 if (tmp->type == IMPLIED_RETURN)
1624 handled |= (tmp->u.implied_return)(expr, tmp->info, rl);
1625 } END_FOR_EACH_PTR(tmp);
1627 out:
1628 free_string(fn);
1629 return handled;
1632 struct range_list *get_range_implications(const char *fn)
1634 struct call_back_list *call_backs;
1635 struct range_list *ret = NULL;
1636 struct fcall_back *tmp;
1638 call_backs = search_callback(func_hash, (char *)fn);
1640 FOR_EACH_PTR(call_backs, tmp) {
1641 if (tmp->type != RANGED_CALL &&
1642 tmp->type != RANGED_EXACT)
1643 continue;
1644 add_ptr_list(&ret, tmp->range);
1645 } END_FOR_EACH_PTR(tmp);
1647 return ret;
1650 void create_function_hook_hash(void)
1652 func_hash = create_function_hashtable(5000);
1655 void register_function_hooks(int id)
1657 add_hook(&match_function_call, CALL_HOOK_AFTER_INLINE);
1658 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
1659 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);