rosenberg: handle bit fields better
[smatch.git] / smatch_function_hooks.c
blob5095c304aaad3f5bfe8529bc19b7a85390ae1667
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;
116 struct db_callback_info {
117 int true_side;
118 int comparison;
119 struct expression *expr;
120 struct range_list *rl;
121 int left;
122 struct stree *stree;
123 struct stree *implied;
124 struct db_implies_list *callbacks;
125 struct db_implies_list *called;
126 int prev_return_id;
127 int cull;
128 int has_states;
129 char *ret_str;
130 struct smatch_state *ret_state;
131 struct expression *var_expr;
132 struct expression_list *fake_param_assign_stack;
133 int handled;
136 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
137 void *info)
139 struct fcall_back *cb;
141 cb = __alloc_fcall_back(0);
142 cb->type = type;
143 cb->u.call_back = call_back;
144 cb->info = info;
145 return cb;
148 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
150 struct fcall_back *cb;
152 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
153 add_callback(func_hash, look_for, cb);
156 void add_function_hook_late(const char *look_for, func_hook *call_back, void *info)
158 struct fcall_back *cb;
160 cb = alloc_fcall_back(REGULAR_CALL_LATE, call_back, info);
161 add_callback(func_hash, look_for, cb);
164 void add_function_assign_hook(const char *look_for, func_hook *call_back,
165 void *info)
167 struct fcall_back *cb;
169 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
170 add_callback(func_hash, look_for, cb);
173 static void register_funcs_from_file_helper(const char *file,
174 func_hook *call_back, void *info,
175 bool assign)
177 struct token *token;
178 const char *func;
179 char name[64];
181 snprintf(name, sizeof(name), "%s.%s", option_project_str, file);
182 token = get_tokens_file(name);
183 if (!token)
184 return;
185 if (token_type(token) != TOKEN_STREAMBEGIN)
186 return;
187 token = token->next;
188 while (token_type(token) != TOKEN_STREAMEND) {
189 if (token_type(token) != TOKEN_IDENT)
190 return;
191 func = show_ident(token->ident);
192 if (assign)
193 add_function_assign_hook(func, call_back, info);
194 else
195 add_function_hook(func, call_back, info);
196 token = token->next;
198 clear_token_alloc();
201 void register_func_hooks_from_file(const char *file,
202 func_hook *call_back, void *info)
204 register_funcs_from_file_helper(file, call_back, info, false);
207 void register_assign_hooks_from_file(const char *file,
208 func_hook *call_back, void *info)
210 register_funcs_from_file_helper(file, call_back, info, true);
213 void add_implied_return_hook(const char *look_for,
214 implied_return_hook *call_back,
215 void *info)
217 struct fcall_back *cb;
219 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
220 add_callback(func_hash, look_for, cb);
223 static void db_helper(struct expression *expr, param_key_hook *call_back, int param, const char *key, void *info)
225 char *name;
226 struct symbol *sym;
228 if (param == -2) {
229 call_back(expr, key, NULL, info);
230 return;
233 name = get_name_sym_from_param_key(expr, param, key, &sym);
234 if (!name || !sym)
235 goto free;
237 call_back(expr, name, sym, info);
238 free:
239 free_string(name);
242 static void param_key_function(const char *fn, struct expression *expr, void *data)
244 struct param_key_data *pkd = data;
245 struct expression *parent;
246 int cnt = 0;
248 parent = expr;
249 while (true) {
250 parent = expr_get_parent_expr(parent);
251 if (!parent || ++cnt >= 5)
252 break;
253 if (parent->type == EXPR_CAST)
254 continue;
255 if (parent->type == EXPR_PREOP && parent->op == '(')
256 continue;
257 break;
260 if (parent && parent->type == EXPR_ASSIGNMENT)
261 expr = parent;
263 db_helper(expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
266 static void param_key_implies_function(const char *fn, struct expression *call_expr,
267 struct expression *assign_expr, void *data)
269 struct param_key_data *pkd = data;
271 db_helper(assign_expr ?: call_expr, pkd->call_back, pkd->param, pkd->key, pkd->info);
274 static struct param_key_data *alloc_pkd(param_key_hook *call_back, int param, const char *key, void *info)
276 struct param_key_data *pkd;
278 pkd = malloc(sizeof(*pkd));
279 pkd->call_back = call_back;
280 pkd->param = param;
281 pkd->key = alloc_string(key);
282 pkd->info = info;
284 return pkd;
287 void add_function_param_key_hook(const char *look_for, param_key_hook *call_back,
288 int param, const char *key, void *info)
290 struct param_key_data *pkd;
292 pkd = alloc_pkd(call_back, param, key, info);
293 add_function_hook(look_for, &param_key_function, pkd);
296 void add_function_param_key_hook_late(const char *look_for, param_key_hook *call_back,
297 int param, const char *key, void *info)
299 struct param_key_data *pkd;
301 pkd = alloc_pkd(call_back, param, key, info);
302 add_function_hook_late(look_for, &param_key_function, pkd);
305 void return_implies_param_key(const char *look_for, sval_t start, sval_t end,
306 param_key_hook *call_back,
307 int param, const char *key, void *info)
309 struct param_key_data *pkd;
311 pkd = alloc_pkd(call_back, param, key, info);
312 return_implies_state_sval(look_for, start, end, &param_key_implies_function, pkd);
315 void return_implies_param_key_exact(const char *look_for, sval_t start, sval_t end,
316 param_key_hook *call_back,
317 int param, const char *key, void *info)
319 struct param_key_data *pkd;
321 pkd = alloc_pkd(call_back, param, key, info);
322 return_implies_exact(look_for, start, end, &param_key_implies_function, pkd);
325 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
326 void *info)
328 struct fcall_back *cb;
330 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
331 add_callback(func_hash, look_for, cb);
334 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
335 void *info)
337 struct fcall_back *cb;
339 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
340 add_callback(func_hash, look_for, cb);
343 void return_implies_state(const char *look_for, long long start, long long end,
344 implication_hook *call_back, void *info)
346 struct fcall_back *cb;
348 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
349 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
350 add_callback(func_hash, look_for, cb);
353 void return_implies_state_sval(const char *look_for, sval_t start, sval_t end,
354 implication_hook *call_back, void *info)
356 struct fcall_back *cb;
358 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
359 cb->range = alloc_range_perm(start, end);
360 add_callback(func_hash, look_for, cb);
363 void return_implies_exact(const char *look_for, sval_t start, sval_t end,
364 implication_hook *call_back, void *info)
366 struct fcall_back *cb;
368 cb = alloc_fcall_back(RANGED_EXACT, call_back, info);
369 cb->range = alloc_range_perm(start, end);
370 add_callback(func_hash, look_for, cb);
373 static struct return_implies_callback *alloc_db_return_callback(int type, bool param_key, void *callback)
375 struct return_implies_callback *cb;
377 cb = __alloc_return_implies_callback(0);
378 cb->type = type;
379 cb->param_key = param_key;
380 cb->callback = callback;
382 return cb;
385 void select_return_states_hook(int type, return_implies_hook *callback)
387 struct return_implies_callback *cb;
389 cb = alloc_db_return_callback(type, false, callback);
390 add_ptr_list(&db_return_states_list, cb);
393 static bool already_called(struct db_implies_list *called, param_key_hook *call_back)
395 struct return_implies_callback *tmp;
397 FOR_EACH_PTR(called, tmp) {
398 if (tmp->pk_callback == call_back)
399 return true;
400 } END_FOR_EACH_PTR(tmp);
402 return false;
405 static void call_db_return_callback(struct db_callback_info *db_info,
406 struct return_implies_callback *cb,
407 int param, char *key, char *value)
409 if (cb->param_key) {
410 if (already_called(db_info->called, cb->pk_callback))
411 return;
412 db_helper(db_info->expr, cb->pk_callback, param, key, NULL);
413 add_ptr_list(&db_info->called, cb);
414 } else {
415 cb->callback(db_info->expr, param, key, value);
419 void select_return_param_key(int type, param_key_hook *callback)
421 struct return_implies_callback *cb;
423 cb = alloc_db_return_callback(type, true, callback);
424 add_ptr_list(&db_return_states_list, cb);
427 void select_return_states_before(void_fn *fn)
429 void_fn *p = malloc(sizeof(*p));
430 p = fn;
431 add_ptr_list(&return_states_before, p);
434 void select_return_states_after(void_fn *fn)
436 void_fn *p = malloc(sizeof(*p));
437 p = fn;
438 add_ptr_list(&return_states_after, p);
441 static void call_return_states_before_hooks(void)
443 void_fn *fn;
445 FOR_EACH_PTR(return_states_before, fn) {
446 (fn)();
447 } END_FOR_EACH_PTR(fn);
450 static int call_call_backs(struct call_back_list *list, int type,
451 const char *fn, struct expression *expr)
453 struct fcall_back *tmp;
454 int handled = 0;
456 FOR_EACH_PTR(list, tmp) {
457 if (tmp->type == type) {
458 (tmp->u.call_back)(fn, expr, tmp->info);
459 handled = 1;
461 } END_FOR_EACH_PTR(tmp);
463 return handled;
466 static void call_function_hooks(struct expression *expr, enum fn_hook_type type)
468 struct call_back_list *call_backs;
469 struct expression *fn;
471 while (expr->type == EXPR_ASSIGNMENT)
472 expr = strip_expr(expr->right);
473 if (expr->type != EXPR_CALL)
474 return;
476 fn = strip_expr(expr->fn);
477 if (fn->type != EXPR_SYMBOL || !fn->symbol)
478 return;
480 call_backs = search_callback(func_hash, (char *)fn->symbol->ident->name);
481 if (!call_backs)
482 return;
484 call_call_backs(call_backs, type, fn->symbol->ident->name, expr);
487 static void call_return_states_after_hooks(struct expression *expr)
489 void_fn *fn;
491 FOR_EACH_PTR(return_states_after, fn) {
492 (fn)();
493 } END_FOR_EACH_PTR(fn);
494 __pass_to_client(expr, FUNCTION_CALL_HOOK_AFTER_DB);
495 call_function_hooks(expr, REGULAR_CALL_LATE);
498 static void call_ranged_call_backs(struct call_back_list *list,
499 const char *fn, struct expression *call_expr,
500 struct expression *assign_expr)
502 struct fcall_back *tmp;
504 FOR_EACH_PTR(list, tmp) {
505 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
506 } END_FOR_EACH_PTR(tmp);
509 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
510 struct data_range *drange)
512 struct call_back_list *ret = NULL;
513 struct fcall_back *tmp;
515 FOR_EACH_PTR(list, tmp) {
516 if (tmp->type != RANGED_CALL &&
517 tmp->type != RANGED_EXACT)
518 continue;
519 if (ranges_equiv(tmp->range, drange))
520 add_ptr_list(&ret, tmp);
521 } END_FOR_EACH_PTR(tmp);
522 return ret;
525 static int in_list_exact_sval(struct range_list *list, struct data_range *drange)
527 struct data_range *tmp;
529 FOR_EACH_PTR(list, tmp) {
530 if (ranges_equiv(tmp, drange))
531 return 1;
532 } END_FOR_EACH_PTR(tmp);
533 return 0;
536 static int assign_ranged_funcs(const char *fn, struct expression *expr,
537 struct call_back_list *call_backs)
539 struct fcall_back *tmp;
540 struct sm_state *sm;
541 char *var_name;
542 struct symbol *sym;
543 struct smatch_state *estate;
544 struct stree *tmp_stree;
545 struct stree *final_states = NULL;
546 struct range_list *handled_ranges = NULL;
547 struct call_back_list *same_range_call_backs = NULL;
548 struct range_list *rl;
549 int handled = 0;
551 if (!call_backs)
552 return 0;
554 var_name = expr_to_var_sym(expr->left, &sym);
555 if (!var_name || !sym)
556 goto free;
558 FOR_EACH_PTR(call_backs, tmp) {
559 if (tmp->type != RANGED_CALL &&
560 tmp->type != RANGED_EXACT)
561 continue;
563 if (in_list_exact_sval(handled_ranges, tmp->range))
564 continue;
565 __push_fake_cur_stree();
566 tack_on(&handled_ranges, tmp->range);
568 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
569 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
570 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
572 rl = alloc_rl(tmp->range->min, tmp->range->max);
573 rl = cast_rl(get_type(expr->left), rl);
574 estate = alloc_estate_rl(rl);
575 set_extra_mod(var_name, sym, expr->left, estate);
577 tmp_stree = __pop_fake_cur_stree();
578 merge_fake_stree(&final_states, tmp_stree);
579 free_stree(&tmp_stree);
580 handled = 1;
581 } END_FOR_EACH_PTR(tmp);
583 FOR_EACH_SM(final_states, sm) {
584 __set_sm(sm);
585 } END_FOR_EACH_SM(sm);
587 free_stree(&final_states);
588 free:
589 free_string(var_name);
590 return handled;
593 static void call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left, struct stree **implied_true, struct stree **implied_false)
595 struct call_back_list *call_backs;
596 struct fcall_back *tmp;
597 const char *fn;
598 struct data_range *value_range;
599 struct stree *true_states = NULL;
600 struct stree *false_states = NULL;
601 struct stree *tmp_stree;
603 *implied_true = NULL;
604 *implied_false = NULL;
605 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
606 return;
607 fn = expr->fn->symbol->ident->name;
608 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
609 if (!call_backs)
610 return;
611 value_range = alloc_range(sval, sval);
613 /* set true states */
614 __push_fake_cur_stree();
615 FOR_EACH_PTR(call_backs, tmp) {
616 if (tmp->type != RANGED_CALL &&
617 tmp->type != RANGED_EXACT)
618 continue;
619 if (!true_comparison_range_LR(comparison, tmp->range, value_range, left))
620 continue;
621 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
622 } END_FOR_EACH_PTR(tmp);
623 tmp_stree = __pop_fake_cur_stree();
624 merge_fake_stree(&true_states, tmp_stree);
625 free_stree(&tmp_stree);
627 /* set false states */
628 __push_fake_cur_stree();
629 FOR_EACH_PTR(call_backs, tmp) {
630 if (tmp->type != RANGED_CALL &&
631 tmp->type != RANGED_EXACT)
632 continue;
633 if (!false_comparison_range_LR(comparison, tmp->range, value_range, left))
634 continue;
635 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
636 } END_FOR_EACH_PTR(tmp);
637 tmp_stree = __pop_fake_cur_stree();
638 merge_fake_stree(&false_states, tmp_stree);
639 free_stree(&tmp_stree);
641 *implied_true = true_states;
642 *implied_false = false_states;
645 static void set_implied_states(struct db_callback_info *db_info)
647 struct sm_state *sm;
649 FOR_EACH_SM(db_info->implied, sm) {
650 __set_sm(sm);
651 } END_FOR_EACH_SM(sm);
653 free_stree(&db_info->implied);
656 static void store_return_state(struct db_callback_info *db_info, const char *ret_str, struct smatch_state *state)
658 db_info->ret_str = alloc_sname(ret_str),
659 db_info->ret_state = state;
662 static bool fake_a_param_assignment(struct expression *expr, const char *ret_str, struct smatch_state *orig)
664 struct expression *arg, *left, *right, *tmp, *fake_assign;
665 char *p;
666 int param;
667 char buf[256];
668 char *str;
670 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
671 return false;
672 left = expr->left;
673 right = expr->right;
675 while (right->type == EXPR_ASSIGNMENT)
676 right = strip_expr(right->right);
677 if (!right || right->type != EXPR_CALL)
678 return false;
680 p = strchr(ret_str, '[');
681 if (!p)
682 return false;
684 p++;
685 if (p[0] == '=' && p[1] == '=')
686 p += 2;
687 if (p[0] != '$')
688 return false;
690 snprintf(buf, sizeof(buf), "%s", p);
692 p = buf;
693 p += 1;
694 param = strtol(p, &p, 10);
696 p = strchr(p, ']');
697 if (!p || *p != ']')
698 return false;
699 *p = '\0';
701 arg = get_argument_from_call_expr(right->args, param);
702 if (!arg)
703 return false;
705 /* There should be a get_other_name() function which returns an expr */
706 tmp = get_assigned_expr(arg);
707 if (tmp)
708 arg = tmp;
711 * This is a sanity check to prevent side effects from evaluating stuff
712 * twice.
714 str = expr_to_chunk_sym_vsl(arg, NULL, NULL);
715 if (!str)
716 return false;
717 free_string(str);
719 right = gen_expression_from_key(arg, buf);
720 if (!right) /* Mostly fails for binops like [$0 + 4032] */
721 return false;
722 fake_assign = assign_expression(left, '=', right);
723 __in_fake_parameter_assign++;
724 __split_expr(fake_assign);
725 __in_fake_parameter_assign--;
728 * If the return is "0-65531[$0->nla_len - 4]" the faked expression
729 * is maybe (-4)-65531 but we know it is in the 0-65531 range so both
730 * parts have to be considered. We use _nomod() because it's not really
731 * another modification, it's just a clarification.
734 if (estate_rl(orig)) {
735 struct smatch_state *faked;
736 struct range_list *rl;
738 faked = get_extra_state(left);
739 if (estate_rl(faked)) {
740 rl = rl_intersection(estate_rl(faked), estate_rl(orig));
741 if (rl)
742 set_extra_expr_nomod(expr, alloc_estate_rl(rl));
746 return true;
749 static void fake_return_assignment(struct db_callback_info *db_info, int type, int param, char *key, char *value)
751 struct expression *call, *left, *right, *assign;
752 int right_param;
754 if (type != PARAM_COMPARE)
755 return;
757 call = db_info->expr;
758 while (call && call->type == EXPR_ASSIGNMENT)
759 call = strip_expr(call->right);
760 if (!call || call->type != EXPR_CALL)
761 return;
763 // TODO: This only handles "$->foo = arg" and not "$->foo = arg->bar".
764 if (param != -1)
765 return;
766 if (!value || strncmp(value, "== $", 4) != 0)
767 return;
768 if (!isdigit(value[4]) || value[5] != '\0')
769 return;
770 right_param = atoi(value + 4);
772 left = gen_expr_from_param_key(db_info->expr, param, key);
773 if (!left)
774 return;
775 right = get_argument_from_call_expr(call->args, right_param);
777 assign = assign_expression(left, '=', right);
778 push_expression(&db_info->fake_param_assign_stack, assign);
781 static void set_fresh_mtag_returns(struct db_callback_info *db_info)
783 struct expression *expr = db_info->expr->left;
784 struct smatch_state *state;
786 if (!db_info->ret_state)
787 return;
789 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
790 state = get_mtag_return(db_info->expr, state);
791 if (!state)
792 return;
794 set_real_absolute(expr, state);
795 set_extra_expr_mod(expr, state);
797 db_info->ret_state = NULL;
798 db_info->ret_str = NULL;
801 static void set_return_assign_state(struct db_callback_info *db_info)
803 struct expression *expr = db_info->expr->left;
804 struct expression *fake_assign;
805 struct smatch_state *state;
807 if (!db_info->ret_state)
808 return;
810 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
811 if (!fake_a_param_assignment(db_info->expr, db_info->ret_str, state))
812 set_extra_expr_mod(expr, state);
814 while ((fake_assign = pop_expression(&db_info->fake_param_assign_stack))) {
815 struct range_list *left, *right;
818 * Originally, I tried to do this as a assignment to record that
819 * a = frob(b) implies that "a->foo == b->foo" etc. But that
820 * caused a problem because then it was recorded that "a->foo"
821 * was modified and recorded as a PARAM_SET in the database.
823 * So now, instead of faking an assignment we use
824 * set_extra_expr_nomod() but it's still recorded as an
825 * assignment in the ->fake_param_assign_stack for legacy
826 * reasons and because it's a handy way to store a left/right
827 * pair.
830 get_absolute_rl(fake_assign->left, &left);
831 get_absolute_rl(fake_assign->right, &right);
832 right = cast_rl(get_type(fake_assign->left), right);
833 // FIXME: add some sanity checks
834 // FIXME: preserve the sm state if possible
835 set_extra_expr_nomod(fake_assign->left, alloc_estate_rl(right));
838 db_info->ret_state = NULL;
839 db_info->ret_str = NULL;
842 static void set_other_side_state(struct db_callback_info *db_info)
844 struct expression *expr = db_info->var_expr;
845 struct smatch_state *state;
847 if (!db_info->ret_state)
848 return;
850 state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
851 set_extra_expr_nomod(expr, state);
852 db_info->ret_state = NULL;
853 db_info->ret_str = NULL;
856 static void handle_ret_equals_param(char *ret_string, struct range_list *rl, struct expression *call)
858 char *str;
859 long long param;
860 struct expression *arg;
861 struct range_list *orig;
863 str = strstr(ret_string, "==$");
864 if (!str)
865 return;
866 str += 3;
867 param = strtoll(str, NULL, 10);
868 arg = get_argument_from_call_expr(call->args, param);
869 if (!arg)
870 return;
871 get_absolute_rl(arg, &orig);
872 rl = rl_intersection(orig, rl);
873 if (!rl)
874 return;
875 set_extra_expr_nomod(arg, alloc_estate_rl(rl));
878 static int impossible_limit(struct db_callback_info *db_info, int param, char *key, char *value)
880 struct expression *expr = db_info->expr;
881 struct expression *arg;
882 struct smatch_state *state;
883 struct range_list *passed;
884 struct range_list *limit;
885 struct symbol *compare_type;
887 while (expr->type == EXPR_ASSIGNMENT)
888 expr = strip_expr(expr->right);
889 if (expr->type != EXPR_CALL)
890 return 0;
892 arg = get_argument_from_call_expr(expr->args, param);
893 if (!arg)
894 return 0;
896 if (strcmp(key, "$") == 0) {
897 if (!get_implied_rl(arg, &passed))
898 return 0;
900 compare_type = get_arg_type(expr->fn, param);
901 } else {
902 char *name;
903 struct symbol *sym;
905 name = get_variable_from_key(arg, key, &sym);
906 if (!name || !sym)
907 return 0;
909 state = get_state(SMATCH_EXTRA, name, sym);
910 if (!state) {
911 free_string(name);
912 return 0;
914 passed = estate_rl(state);
915 if (!passed || is_whole_rl(passed)) {
916 free_string(name);
917 return 0;
920 compare_type = get_member_type_from_key(arg, key);
923 passed = cast_rl(compare_type, passed);
924 call_results_to_rl(expr, compare_type, value, &limit);
925 if (!limit || is_whole_rl(limit))
926 return 0;
927 if (possibly_true_rl(passed, SPECIAL_EQUAL, limit))
928 return 0;
929 if (option_debug || local_debug)
930 sm_msg("impossible: %d '%s' limit '%s' == '%s' return='%s'", param, key, show_rl(passed), value, db_info->ret_str);
931 return 1;
934 static int is_impossible_data(int type, struct db_callback_info *db_info, int param, char *key, char *value)
936 if (type == PARAM_LIMIT && impossible_limit(db_info, param, key, value))
937 return 1;
938 if (type == COMPARE_LIMIT && param_compare_limit_is_impossible(db_info->expr, param, key, value)) {
939 if (local_debug)
940 sm_msg("param_compare_limit_is_impossible: %d %s %s", param, key, value);
941 return 1;
943 return 0;
946 static int func_type_mismatch(struct expression *expr, const char *value)
948 struct symbol *type;
950 /* This makes faking returns easier */
951 if (!value || value[0] == '\0')
952 return 0;
954 while (expr->type == EXPR_ASSIGNMENT)
955 expr = strip_expr(expr->right);
958 * Short cut: We only care about function pointers that are struct
959 * members.
962 if (expr->fn->type == EXPR_SYMBOL)
963 return 0;
965 type = get_type(expr->fn);
966 if (!type)
967 return 0;
968 if (type->type == SYM_PTR)
969 type = get_real_base_type(type);
971 if (strcmp(type_to_str(type), value) == 0)
972 return 0;
974 return 1;
977 static int db_compare_callback(void *_info, int argc, char **argv, char **azColName)
979 struct db_callback_info *db_info = _info;
980 struct range_list *var_rl = db_info->rl;
981 struct range_list *ret_range;
982 int type, param;
983 char *ret_str, *key, *value;
984 struct return_implies_callback *tmp;
985 struct stree *stree;
986 int return_id;
987 int comparison;
989 if (argc != 6)
990 return 0;
992 return_id = atoi(argv[0]);
993 ret_str = argv[1];
994 type = atoi(argv[2]);
995 param = atoi(argv[3]);
996 key = argv[4];
997 value = argv[5];
999 db_info->has_states = 1;
1000 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1001 set_other_side_state(db_info);
1002 set_implied_states(db_info);
1003 free_ptr_list(&db_info->called);
1004 stree = __pop_fake_cur_stree();
1005 if (!db_info->cull)
1006 merge_fake_stree(&db_info->stree, stree);
1007 free_stree(&stree);
1008 __push_fake_cur_stree();
1009 db_info->cull = 0;
1011 db_info->prev_return_id = return_id;
1013 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1014 db_info->cull = 1;
1015 if (db_info->cull)
1016 return 0;
1017 if (type == CULL_PATH) {
1018 db_info->cull = 1;
1019 return 0;
1022 if (is_impossible_data(type, db_info, param, key, value)) {
1023 db_info->cull = 1;
1024 return 0;
1027 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1028 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1029 if (!ret_range)
1030 ret_range = alloc_whole_rl(get_type(db_info->expr));
1032 comparison = db_info->comparison;
1033 if (db_info->left)
1034 comparison = flip_comparison(comparison);
1036 if (db_info->true_side) {
1037 if (!possibly_true_rl(var_rl, comparison, ret_range))
1038 return 0;
1039 if (type == PARAM_LIMIT)
1040 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1041 else if (type > PARAM_LIMIT)
1042 set_implied_states(db_info);
1043 filter_by_comparison(&var_rl, comparison, ret_range);
1044 filter_by_comparison(&ret_range, flip_comparison(comparison), var_rl);
1045 } else {
1046 if (!possibly_false_rl(var_rl, comparison, ret_range))
1047 return 0;
1048 if (type == PARAM_LIMIT)
1049 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1050 else if (type > PARAM_LIMIT)
1051 set_implied_states(db_info);
1052 filter_by_comparison(&var_rl, negate_comparison(comparison), ret_range);
1053 filter_by_comparison(&ret_range, flip_comparison(negate_comparison(comparison)), var_rl);
1056 handle_ret_equals_param(ret_str, ret_range, db_info->expr);
1058 if (type == INTERNAL) {
1059 set_state(-1, "unnull_path", NULL, &true_state);
1060 __add_return_comparison(strip_expr(db_info->expr), ret_str);
1061 __add_return_to_param_mapping(db_info->expr, ret_str);
1062 store_return_state(db_info, ret_str, alloc_estate_rl(clone_rl(var_rl)));
1065 FOR_EACH_PTR(db_info->callbacks, tmp) {
1066 if (tmp->type == type)
1067 call_db_return_callback(db_info, tmp, param, key, value);
1068 } END_FOR_EACH_PTR(tmp);
1070 fake_return_assignment(db_info, type, param, key, value);
1072 return 0;
1075 static void compare_db_return_states_callbacks(struct expression *left, int comparison, struct expression *right, struct stree *implied_true, struct stree *implied_false)
1077 struct stree *orig_states;
1078 struct stree *stree;
1079 struct stree *true_states;
1080 struct stree *false_states;
1081 struct sm_state *sm;
1082 struct db_callback_info db_info = {};
1083 struct expression *var_expr;
1084 struct expression *call_expr;
1085 struct range_list *rl;
1086 int call_on_left;
1088 orig_states = clone_stree(__get_cur_stree());
1090 /* legacy cruft. need to fix call_implies_callbacks(). */
1091 call_on_left = 1;
1092 call_expr = left;
1093 var_expr = right;
1094 if (left->type != EXPR_CALL) {
1095 call_on_left = 0;
1096 call_expr = right;
1097 var_expr = left;
1100 get_absolute_rl(var_expr, &rl);
1102 db_info.comparison = comparison;
1103 db_info.expr = call_expr;
1104 db_info.rl = rl;
1105 db_info.left = call_on_left;
1106 db_info.callbacks = db_return_states_list;
1107 db_info.var_expr = var_expr;
1109 call_return_states_before_hooks();
1111 db_info.true_side = 1;
1112 db_info.stree = NULL;
1113 db_info.prev_return_id = -1;
1114 __push_fake_cur_stree();
1115 sql_select_return_states("return_id, return, type, parameter, key, value",
1116 call_expr, db_compare_callback, &db_info);
1117 set_other_side_state(&db_info);
1118 set_implied_states(&db_info);
1119 free_ptr_list(&db_info.called);
1120 stree = __pop_fake_cur_stree();
1121 if (!db_info.cull)
1122 merge_fake_stree(&db_info.stree, stree);
1123 free_stree(&stree);
1124 true_states = db_info.stree;
1125 if (!true_states && db_info.has_states) {
1126 __push_fake_cur_stree();
1127 set_path_impossible();
1128 true_states = __pop_fake_cur_stree();
1131 nullify_path();
1132 __unnullify_path();
1133 FOR_EACH_SM(orig_states, sm) {
1134 __set_sm_cur_stree(sm);
1135 } END_FOR_EACH_SM(sm);
1137 db_info.true_side = 0;
1138 db_info.stree = NULL;
1139 db_info.prev_return_id = -1;
1140 db_info.cull = 0;
1141 __push_fake_cur_stree();
1142 sql_select_return_states("return_id, return, type, parameter, key, value", call_expr,
1143 db_compare_callback, &db_info);
1144 set_other_side_state(&db_info);
1145 set_implied_states(&db_info);
1146 free_ptr_list(&db_info.called);
1147 stree = __pop_fake_cur_stree();
1148 if (!db_info.cull)
1149 merge_fake_stree(&db_info.stree, stree);
1150 free_stree(&stree);
1151 false_states = db_info.stree;
1152 if (!false_states && db_info.has_states) {
1153 __push_fake_cur_stree();
1154 set_path_impossible();
1155 false_states = __pop_fake_cur_stree();
1158 nullify_path();
1159 __unnullify_path();
1160 FOR_EACH_SM(orig_states, sm) {
1161 __set_sm_cur_stree(sm);
1162 } END_FOR_EACH_SM(sm);
1164 free_stree(&orig_states);
1166 FOR_EACH_SM(true_states, sm) {
1167 __set_true_false_sm(sm, NULL);
1168 } END_FOR_EACH_SM(sm);
1169 FOR_EACH_SM(false_states, sm) {
1170 __set_true_false_sm(NULL, sm);
1171 } END_FOR_EACH_SM(sm);
1173 free_stree(&true_states);
1174 free_stree(&false_states);
1176 call_return_states_after_hooks(call_expr);
1178 FOR_EACH_SM(implied_true, sm) {
1179 __set_true_false_sm(sm, NULL);
1180 } END_FOR_EACH_SM(sm);
1181 FOR_EACH_SM(implied_false, sm) {
1182 __set_true_false_sm(NULL, sm);
1183 } END_FOR_EACH_SM(sm);
1186 void function_comparison(struct expression *left, int comparison, struct expression *right)
1188 struct expression *var_expr;
1189 struct expression *call_expr;
1190 struct stree *implied_true = NULL;
1191 struct stree *implied_false = NULL;
1192 struct range_list *rl;
1193 sval_t sval;
1194 int call_on_left;
1196 if (unreachable())
1197 return;
1199 /* legacy cruft. need to fix call_implies_callbacks(). */
1200 call_on_left = 1;
1201 call_expr = left;
1202 var_expr = right;
1203 if (left->type != EXPR_CALL) {
1204 call_on_left = 0;
1205 call_expr = right;
1206 var_expr = left;
1209 get_absolute_rl(var_expr, &rl);
1211 if (rl_to_sval(rl, &sval))
1212 call_implies_callbacks(comparison, call_expr, sval, call_on_left, &implied_true, &implied_false);
1214 compare_db_return_states_callbacks(left, comparison, right, implied_true, implied_false);
1215 free_stree(&implied_true);
1216 free_stree(&implied_false);
1219 static void call_ranged_return_hooks(struct db_callback_info *db_info)
1221 struct call_back_list *call_backs;
1222 struct range_list *range_rl;
1223 struct expression *expr;
1224 struct fcall_back *tmp;
1225 char *fn;
1227 expr = strip_expr(db_info->expr);
1228 while (expr->type == EXPR_ASSIGNMENT)
1229 expr = strip_expr(expr->right);
1230 if (expr->type != EXPR_CALL ||
1231 expr->fn->type != EXPR_SYMBOL)
1232 return;
1234 fn = expr->fn->symbol_name->name;
1236 call_backs = search_callback(func_hash, fn);
1237 FOR_EACH_PTR(call_backs, tmp) {
1238 if (tmp->type != RANGED_CALL)
1239 continue;
1240 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1241 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1242 if (possibly_true_rl(range_rl, SPECIAL_EQUAL, estate_rl(db_info->ret_state)))
1243 (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
1244 } END_FOR_EACH_PTR(tmp);
1246 FOR_EACH_PTR(call_backs, tmp) {
1247 if (tmp->type != RANGED_EXACT)
1248 continue;
1249 if (!estate_rl(db_info->ret_state))
1250 continue;
1252 range_rl = alloc_rl(tmp->range->min, tmp->range->max);
1253 range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
1256 * If there is an returned value out of range then this is not
1257 * an exact match. In other words, "0,4096-ptr_max" is not
1258 * necessarily a valid match.
1261 if (remove_range(estate_rl(db_info->ret_state),
1262 rl_min(range_rl), rl_max(range_rl)))
1263 continue;
1264 (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
1265 } END_FOR_EACH_PTR(tmp);
1268 static int db_assign_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1270 struct db_callback_info *db_info = _info;
1271 struct range_list *ret_range;
1272 int type, param;
1273 char *ret_str, *key, *value;
1274 struct return_implies_callback *tmp;
1275 struct stree *stree;
1276 int return_id;
1278 if (argc != 6)
1279 return 0;
1281 return_id = atoi(argv[0]);
1282 ret_str = argv[1];
1283 type = atoi(argv[2]);
1284 param = atoi(argv[3]);
1285 key = argv[4];
1286 value = argv[5];
1288 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1289 call_ranged_return_hooks(db_info);
1290 set_return_assign_state(db_info);
1291 set_implied_states(db_info);
1292 free_ptr_list(&db_info->called);
1293 stree = __pop_fake_cur_stree();
1294 if (!db_info->cull)
1295 merge_fake_stree(&db_info->stree, stree);
1296 free_stree(&stree);
1297 __push_fake_cur_stree();
1298 db_info->cull = 0;
1300 db_info->prev_return_id = return_id;
1302 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1303 db_info->cull = 1;
1304 if (db_info->cull)
1305 return 0;
1306 if (type == CULL_PATH) {
1307 db_info->cull = 1;
1308 return 0;
1310 if (is_impossible_data(type, db_info, param, key, value)) {
1311 db_info->cull = 1;
1312 return 0;
1315 if (type == PARAM_LIMIT)
1316 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1317 else if (type > PARAM_LIMIT)
1318 set_implied_states(db_info);
1320 db_info->handled = 1;
1321 call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), ret_str, &ret_range);
1322 if (!ret_range)
1323 ret_range = alloc_whole_rl(get_type(strip_expr(db_info->expr->right)));
1324 ret_range = cast_rl(get_type(db_info->expr->right), ret_range);
1326 if (type == INTERNAL) {
1327 set_state(-1, "unnull_path", NULL, &true_state);
1328 __add_return_comparison(strip_expr(db_info->expr->right), ret_str);
1329 __add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), ret_str);
1330 __add_return_to_param_mapping(db_info->expr, ret_str);
1331 store_return_state(db_info, ret_str, alloc_estate_rl(ret_range));
1332 set_fresh_mtag_returns(db_info);
1335 FOR_EACH_PTR(db_return_states_list, tmp) {
1336 if (tmp->type == type)
1337 call_db_return_callback(db_info, tmp, param, key, value);
1338 } END_FOR_EACH_PTR(tmp);
1340 fake_return_assignment(db_info, type, param, key, value);
1342 return 0;
1345 static int db_return_states_assign(struct expression *expr)
1347 struct expression *right;
1348 struct sm_state *sm;
1349 struct stree *stree;
1350 struct db_callback_info db_info = {};
1352 right = strip_expr(expr->right);
1354 db_info.prev_return_id = -1;
1355 db_info.expr = expr;
1356 db_info.stree = NULL;
1357 db_info.handled = 0;
1359 call_return_states_before_hooks();
1361 __push_fake_cur_stree();
1362 sql_select_return_states("return_id, return, type, parameter, key, value",
1363 right, db_assign_return_states_callback, &db_info);
1364 if (option_debug) {
1365 sm_msg("%s return_id %d return_ranges %s",
1366 db_info.cull ? "culled" : "merging",
1367 db_info.prev_return_id,
1368 db_info.ret_state ? db_info.ret_state->name : "'<empty>'");
1370 if (db_info.handled)
1371 call_ranged_return_hooks(&db_info);
1372 set_return_assign_state(&db_info);
1373 set_implied_states(&db_info);
1374 free_ptr_list(&db_info.called);
1375 stree = __pop_fake_cur_stree();
1376 if (!db_info.cull)
1377 merge_fake_stree(&db_info.stree, stree);
1378 free_stree(&stree);
1380 if (!db_info.stree && db_info.cull) { /* this means we culled everything */
1381 set_extra_expr_mod(expr->left, alloc_estate_whole(get_type(expr->left)));
1382 set_path_impossible();
1384 FOR_EACH_SM(db_info.stree, sm) {
1385 __set_sm(sm);
1386 } END_FOR_EACH_SM(sm);
1388 free_stree(&db_info.stree);
1389 call_return_states_after_hooks(right);
1391 return db_info.handled;
1394 static int handle_implied_return(struct expression *expr)
1396 struct range_list *rl;
1398 if (!get_implied_return(expr->right, &rl))
1399 return 0;
1400 rl = cast_rl(get_type(expr->left), rl);
1401 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1402 return 1;
1405 static void match_assign_call(struct expression *expr)
1407 struct call_back_list *call_backs;
1408 const char *fn;
1409 struct expression *right;
1410 int handled = 0;
1411 struct range_list *rl;
1413 if (expr->op != '=')
1414 return;
1416 right = strip_expr(expr->right);
1417 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
1418 handled |= db_return_states_assign(expr);
1419 if (!handled)
1420 goto assigned_unknown;
1421 return;
1423 if (is_fake_call(right))
1424 return;
1426 fn = right->fn->symbol->ident->name;
1427 call_backs = search_callback(func_hash, (char *)fn);
1430 * The ordering here is sort of important.
1431 * One example, of how this matters is that when we do:
1433 * len = strlen(str);
1435 * That is handled by smatch_common_functions.c and smatch_strlen.c.
1436 * They use implied_return and function_assign_hook respectively.
1437 * We want to get the implied return first before we do the function
1438 * assignment hook otherwise we end up writing the wrong thing for len
1439 * in smatch_extra.c because we assume that it already holds the
1440 * strlen() when we haven't set it yet.
1443 if (db_return_states_assign(expr))
1444 handled = 1;
1445 else
1446 handled = assign_ranged_funcs(fn, expr, call_backs);
1447 handled |= handle_implied_return(expr);
1450 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
1452 if (handled)
1453 return;
1455 assigned_unknown:
1456 get_absolute_rl(expr->right, &rl);
1457 rl = cast_rl(get_type(expr->left), rl);
1458 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
1461 static int db_return_states_callback(void *_info, int argc, char **argv, char **azColName)
1463 struct db_callback_info *db_info = _info;
1464 struct range_list *ret_range;
1465 int type, param;
1466 char *ret_str, *key, *value;
1467 struct return_implies_callback *tmp;
1468 struct stree *stree;
1469 int return_id;
1470 char buf[64];
1472 if (argc != 6)
1473 return 0;
1475 return_id = atoi(argv[0]);
1476 ret_str = argv[1];
1477 type = atoi(argv[2]);
1478 param = atoi(argv[3]);
1479 key = argv[4];
1480 value = argv[5];
1482 if (db_info->prev_return_id != -1 && type == INTERNAL) {
1483 call_ranged_return_hooks(db_info);
1484 set_implied_states(db_info);
1485 free_ptr_list(&db_info->called);
1486 stree = __pop_fake_cur_stree();
1487 if (!db_info->cull)
1488 merge_fake_stree(&db_info->stree, stree);
1489 free_stree(&stree);
1490 __push_fake_cur_stree();
1491 __unnullify_path();
1492 db_info->cull = 0;
1494 db_info->prev_return_id = return_id;
1496 if (type == INTERNAL && func_type_mismatch(db_info->expr, value))
1497 db_info->cull = 1;
1498 if (db_info->cull)
1499 return 0;
1500 if (type == CULL_PATH) {
1501 db_info->cull = 1;
1502 return 0;
1504 if (is_impossible_data(type, db_info, param, key, value)) {
1505 db_info->cull = 1;
1506 return 0;
1509 if (type == PARAM_LIMIT)
1510 param_limit_implications(db_info->expr, param, key, value, &db_info->implied);
1511 else if (type > PARAM_LIMIT)
1512 set_implied_states(db_info);
1514 call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
1515 ret_range = cast_rl(get_type(db_info->expr), ret_range);
1517 if (type == INTERNAL) {
1518 struct smatch_state *state;
1520 set_state(-1, "unnull_path", NULL, &true_state);
1521 __add_return_comparison(strip_expr(db_info->expr), ret_str);
1522 __add_return_to_param_mapping(db_info->expr, ret_str);
1524 * We want to store the return values so that we can split the strees
1525 * in smatch_db.c. This uses set_state() directly because it's not a
1526 * real smatch_extra state.
1528 snprintf(buf, sizeof(buf), "return %p", db_info->expr);
1529 state = alloc_estate_rl(ret_range);
1530 set_state(SMATCH_EXTRA, buf, NULL, state);
1531 store_return_state(db_info, ret_str, state);
1534 FOR_EACH_PTR(db_return_states_list, tmp) {
1535 if (tmp->type == type)
1536 call_db_return_callback(db_info, tmp, param, key, value);
1537 } END_FOR_EACH_PTR(tmp);
1539 fake_return_assignment(db_info, type, param, key, value);
1541 return 0;
1544 static void db_return_states(struct expression *expr)
1546 struct sm_state *sm;
1547 struct stree *stree;
1548 struct db_callback_info db_info = {};
1550 if (!__get_cur_stree()) /* no return functions */
1551 return;
1553 db_info.prev_return_id = -1;
1554 db_info.expr = expr;
1555 db_info.stree = NULL;
1557 call_return_states_before_hooks();
1559 __push_fake_cur_stree();
1560 __unnullify_path();
1561 sql_select_return_states("return_id, return, type, parameter, key, value",
1562 expr, db_return_states_callback, &db_info);
1563 call_ranged_return_hooks(&db_info);
1564 set_implied_states(&db_info);
1565 free_ptr_list(&db_info.called);
1566 stree = __pop_fake_cur_stree();
1567 if (!db_info.cull)
1568 merge_fake_stree(&db_info.stree, stree);
1569 free_stree(&stree);
1571 FOR_EACH_SM(db_info.stree, sm) {
1572 __set_sm(sm);
1573 } END_FOR_EACH_SM(sm);
1575 free_stree(&db_info.stree);
1576 call_return_states_after_hooks(expr);
1579 static int is_condition_call(struct expression *expr)
1581 struct expression *tmp;
1583 FOR_EACH_PTR_REVERSE(big_condition_stack, tmp) {
1584 if (expr == tmp || expr_get_parent_expr(expr) == tmp)
1585 return 1;
1586 if (tmp->pos.line < expr->pos.line)
1587 return 0;
1588 } END_FOR_EACH_PTR_REVERSE(tmp);
1590 return 0;
1593 static void db_return_states_call(struct expression *expr)
1595 if (unreachable())
1596 return;
1598 if (is_assigned_call(expr) || is_fake_assigned_call(expr))
1599 return;
1600 if (is_condition_call(expr))
1601 return;
1602 db_return_states(expr);
1605 static void match_function_call(struct expression *expr)
1607 call_function_hooks(expr, REGULAR_CALL);
1608 db_return_states_call(expr);
1611 static void match_macro_assign(struct expression *expr)
1613 struct call_back_list *call_backs;
1614 const char *macro;
1615 struct expression *right;
1617 right = strip_expr(expr->right);
1618 macro = get_macro_name(right->pos);
1619 call_backs = search_callback(func_hash, (char *)macro);
1620 if (!call_backs)
1621 return;
1622 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
1623 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
1626 int get_implied_return(struct expression *expr, struct range_list **rl)
1628 struct call_back_list *call_backs;
1629 struct fcall_back *tmp;
1630 int handled = 0;
1631 char *fn;
1633 *rl = NULL;
1635 expr = strip_expr(expr);
1636 fn = expr_to_var(expr->fn);
1637 if (!fn)
1638 goto out;
1640 call_backs = search_callback(func_hash, fn);
1642 FOR_EACH_PTR(call_backs, tmp) {
1643 if (tmp->type == IMPLIED_RETURN)
1644 handled |= (tmp->u.implied_return)(expr, tmp->info, rl);
1645 } END_FOR_EACH_PTR(tmp);
1647 out:
1648 free_string(fn);
1649 return handled;
1652 struct range_list *get_range_implications(const char *fn)
1654 struct call_back_list *call_backs;
1655 struct range_list *ret = NULL;
1656 struct fcall_back *tmp;
1658 call_backs = search_callback(func_hash, (char *)fn);
1660 FOR_EACH_PTR(call_backs, tmp) {
1661 if (tmp->type != RANGED_CALL &&
1662 tmp->type != RANGED_EXACT)
1663 continue;
1664 add_ptr_list(&ret, tmp->range);
1665 } END_FOR_EACH_PTR(tmp);
1667 return ret;
1670 void create_function_hook_hash(void)
1672 func_hash = create_function_hashtable(5000);
1675 void register_function_hooks(int id)
1677 add_hook(&match_function_call, CALL_HOOK_AFTER_INLINE);
1678 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
1679 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);