2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
11 * There are several types of function hooks:
12 * add_function_hook() - For any time a function is called.
13 * add_function_assign_hook() - foo = the_function().
14 * add_implied_return_hook() - Calculates the implied return value.
15 * add_macro_assign_hook() - foo = the_macro().
16 * return_implies_state() - For when a return value of 1 implies locked
17 * and 0 implies unlocked. etc. etc.
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
30 struct data_range
*range
;
33 implication_hook
*ranged
;
34 implied_return_hook
*implied_return
;
39 ALLOCATOR(fcall_back
, "call backs");
40 DECLARE_PTR_LIST(call_back_list
, struct fcall_back
);
42 DEFINE_FUNCTION_HASHTABLE_STATIC(callback
, struct fcall_back
, struct call_back_list
);
43 static struct hashtable
*func_hash
;
45 #define REGULAR_CALL 0
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback
{
54 return_implies_hook
*callback
;
56 ALLOCATOR(return_implies_callback
, "return_implies callbacks");
57 DECLARE_PTR_LIST(db_implies_list
, struct return_implies_callback
);
58 static struct db_implies_list
*db_implies_list
;
59 static struct db_implies_list
*db_return_states_list
;
61 static struct fcall_back
*alloc_fcall_back(int type
, void *call_back
,
64 struct fcall_back
*cb
;
66 cb
= __alloc_fcall_back(0);
68 cb
->u
.call_back
= call_back
;
73 void add_function_hook(const char *look_for
, func_hook
*call_back
, void *info
)
75 struct fcall_back
*cb
;
77 cb
= alloc_fcall_back(REGULAR_CALL
, call_back
, info
);
78 add_callback(func_hash
, look_for
, cb
);
81 void add_function_assign_hook(const char *look_for
, func_hook
*call_back
,
84 struct fcall_back
*cb
;
86 cb
= alloc_fcall_back(ASSIGN_CALL
, call_back
, info
);
87 add_callback(func_hash
, look_for
, cb
);
90 void add_implied_return_hook(const char *look_for
,
91 implied_return_hook
*call_back
,
94 struct fcall_back
*cb
;
96 cb
= alloc_fcall_back(IMPLIED_RETURN
, call_back
, info
);
97 add_callback(func_hash
, look_for
, cb
);
100 void add_macro_assign_hook(const char *look_for
, func_hook
*call_back
,
103 struct fcall_back
*cb
;
105 cb
= alloc_fcall_back(MACRO_ASSIGN
, call_back
, info
);
106 add_callback(func_hash
, look_for
, cb
);
109 void add_macro_assign_hook_extra(const char *look_for
, func_hook
*call_back
,
112 struct fcall_back
*cb
;
114 cb
= alloc_fcall_back(MACRO_ASSIGN_EXTRA
, call_back
, info
);
115 add_callback(func_hash
, look_for
, cb
);
118 void return_implies_state(const char *look_for
, long long start
, long long end
,
119 implication_hook
*call_back
, void *info
)
121 struct fcall_back
*cb
;
123 cb
= alloc_fcall_back(RANGED_CALL
, call_back
, info
);
124 cb
->range
= alloc_range_perm(ll_to_sval(start
), ll_to_sval(end
));
125 add_callback(func_hash
, look_for
, cb
);
128 void add_db_return_implies_callback(int type
, return_implies_hook
*callback
)
130 struct return_implies_callback
*cb
= __alloc_return_implies_callback(0);
133 cb
->callback
= callback
;
134 add_ptr_list(&db_implies_list
, cb
);
137 void add_db_return_states_callback(int type
, return_implies_hook
*callback
)
139 struct return_implies_callback
*cb
= __alloc_return_implies_callback(0);
142 cb
->callback
= callback
;
143 add_ptr_list(&db_return_states_list
, cb
);
146 static int call_call_backs(struct call_back_list
*list
, int type
,
147 const char *fn
, struct expression
*expr
)
149 struct fcall_back
*tmp
;
152 FOR_EACH_PTR(list
, tmp
) {
153 if (tmp
->type
== type
) {
154 (tmp
->u
.call_back
)(fn
, expr
, tmp
->info
);
157 } END_FOR_EACH_PTR(tmp
);
162 static void call_ranged_call_backs(struct call_back_list
*list
,
163 const char *fn
, struct expression
*call_expr
,
164 struct expression
*assign_expr
)
166 struct fcall_back
*tmp
;
168 FOR_EACH_PTR(list
, tmp
) {
169 (tmp
->u
.ranged
)(fn
, call_expr
, assign_expr
, tmp
->info
);
170 } END_FOR_EACH_PTR(tmp
);
173 static struct call_back_list
*get_same_ranged_call_backs(struct call_back_list
*list
,
174 struct data_range
*drange
)
176 struct call_back_list
*ret
= NULL
;
177 struct fcall_back
*tmp
;
179 FOR_EACH_PTR(list
, tmp
) {
180 if (tmp
->type
!= RANGED_CALL
)
182 if (ranges_equiv(tmp
->range
, drange
))
183 add_ptr_list(&ret
, tmp
);
184 } END_FOR_EACH_PTR(tmp
);
188 static int in_list_exact_sval(struct range_list
*list
, struct data_range
*drange
)
190 struct data_range
*tmp
;
192 FOR_EACH_PTR(list
, tmp
) {
193 if (ranges_equiv(tmp
, drange
))
195 } END_FOR_EACH_PTR(tmp
);
199 static int assign_ranged_funcs(const char *fn
, struct expression
*expr
,
200 struct call_back_list
*call_backs
)
202 struct fcall_back
*tmp
;
206 struct smatch_state
*estate
;
207 struct state_list
*tmp_slist
;
208 struct state_list
*final_states
= NULL
;
209 struct range_list
*handled_ranges
= NULL
;
210 struct call_back_list
*same_range_call_backs
= NULL
;
216 var_name
= get_variable_from_expr(expr
->left
, &sym
);
217 if (!var_name
|| !sym
)
220 FOR_EACH_PTR(call_backs
, tmp
) {
221 if (tmp
->type
!= RANGED_CALL
)
224 if (in_list_exact_sval(handled_ranges
, tmp
->range
))
226 __push_fake_cur_slist();
227 tack_on(&handled_ranges
, tmp
->range
);
229 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp
->range
);
230 call_ranged_call_backs(same_range_call_backs
, fn
, expr
->right
, expr
);
231 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
233 estate
= alloc_estate_range(tmp
->range
->min
, tmp
->range
->max
);
234 set_extra_mod(var_name
, sym
, estate
);
236 tmp_slist
= __pop_fake_cur_slist();
237 merge_slist(&final_states
, tmp_slist
);
238 free_slist(&tmp_slist
);
240 } END_FOR_EACH_PTR(tmp
);
242 FOR_EACH_PTR(final_states
, sm
) {
244 } END_FOR_EACH_PTR(sm
);
246 free_slist(&final_states
);
248 free_string(var_name
);
252 static int call_implies_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
254 struct call_back_list
*call_backs
;
255 struct fcall_back
*tmp
;
257 struct data_range
*value_range
;
258 struct state_list
*true_states
= NULL
;
259 struct state_list
*false_states
= NULL
;
260 struct state_list
*tmp_slist
;
263 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
265 fn
= expr
->fn
->symbol
->ident
->name
;
266 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
269 value_range
= alloc_range(sval
, sval
);
271 /* set true states */
272 __push_fake_cur_slist();
273 FOR_EACH_PTR(call_backs
, tmp
) {
274 if (tmp
->type
!= RANGED_CALL
)
276 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
278 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
279 } END_FOR_EACH_PTR(tmp
);
280 tmp_slist
= __pop_fake_cur_slist();
281 merge_slist(&true_states
, tmp_slist
);
282 free_slist(&tmp_slist
);
284 /* set false states */
285 __push_fake_cur_slist();
286 FOR_EACH_PTR(call_backs
, tmp
) {
287 if (tmp
->type
!= RANGED_CALL
)
289 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
291 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
292 } END_FOR_EACH_PTR(tmp
);
293 tmp_slist
= __pop_fake_cur_slist();
294 merge_slist(&false_states
, tmp_slist
);
295 free_slist(&tmp_slist
);
297 FOR_EACH_PTR(true_states
, sm
) {
298 __set_true_false_sm(sm
, NULL
);
299 } END_FOR_EACH_PTR(sm
);
300 FOR_EACH_PTR(false_states
, sm
) {
301 __set_true_false_sm(NULL
, sm
);
302 } END_FOR_EACH_PTR(sm
);
304 free_slist(&true_states
);
305 free_slist(&false_states
);
309 struct db_callback_info
{
312 struct expression
*expr
;
313 struct range_list
*rl
;
315 struct state_list
*slist
;
316 struct db_implies_list
*callbacks
;
318 static struct db_callback_info db_info
;
319 static int db_compare_callback(void *unused
, int argc
, char **argv
, char **azColName
)
321 struct range_list
*ret_range
;
324 struct return_implies_callback
*tmp
;
329 parse_value_ranges_type(get_type(db_info
.expr
), argv
[0], &ret_range
);
330 type
= atoi(argv
[1]);
331 param
= atoi(argv
[2]);
335 if (db_info
.true_side
) {
336 if (!possibly_true_range_lists_lr(db_info
.comparison
,
337 ret_range
, db_info
.rl
,
341 if (!possibly_false_range_lists_lr(db_info
.comparison
,
342 ret_range
, db_info
.rl
,
347 FOR_EACH_PTR(db_info
.callbacks
, tmp
) {
348 if (tmp
->type
== type
)
349 tmp
->callback(db_info
.expr
, param
, key
, value
);
350 } END_FOR_EACH_PTR(tmp
);
354 void compare_db_implies_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
357 static char sql_filter
[1024];
358 struct state_list
*true_states
;
359 struct state_list
*false_states
;
362 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
365 sym
= expr
->fn
->symbol
;
369 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
370 snprintf(sql_filter
, 1024,
371 "file = '%s' and function = '%s' and static = '1';",
372 get_filename(), sym
->ident
->name
);
374 snprintf(sql_filter
, 1024,
375 "function = '%s' and static = '0';", sym
->ident
->name
);
378 db_info
.comparison
= comparison
;
380 db_info
.rl
= alloc_range_list(sval
, sval
);
382 db_info
.callbacks
= db_implies_list
;
384 db_info
.true_side
= 1;
385 __push_fake_cur_slist();
386 run_sql(db_compare_callback
,
387 "select return, type, parameter, key, value from return_implies where %s",
389 true_states
= __pop_fake_cur_slist();
391 db_info
.true_side
= 0;
392 __push_fake_cur_slist();
393 run_sql(db_compare_callback
,
394 "select return, type, parameter, key, value from return_implies where %s",
396 false_states
= __pop_fake_cur_slist();
398 FOR_EACH_PTR(true_states
, sm
) {
399 __set_true_false_sm(sm
, NULL
);
400 } END_FOR_EACH_PTR(sm
);
401 FOR_EACH_PTR(false_states
, sm
) {
402 __set_true_false_sm(NULL
, sm
);
403 } END_FOR_EACH_PTR(sm
);
405 free_slist(&true_states
);
406 free_slist(&false_states
);
409 void compare_db_return_states_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
412 static char sql_filter
[1024];
413 struct state_list
*true_states
;
414 struct state_list
*false_states
;
417 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
420 sym
= expr
->fn
->symbol
;
424 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
425 snprintf(sql_filter
, 1024,
426 "file = '%s' and function = '%s' and static = '1';",
427 get_filename(), sym
->ident
->name
);
429 snprintf(sql_filter
, 1024,
430 "function = '%s' and static = '0';", sym
->ident
->name
);
433 db_info
.comparison
= comparison
;
435 db_info
.rl
= alloc_range_list(sval
, sval
);
437 db_info
.callbacks
= db_return_states_list
;
439 db_info
.true_side
= 1;
440 __push_fake_cur_slist();
441 run_sql(db_compare_callback
,
442 "select return, type, parameter, key, value from return_states where %s",
444 true_states
= __pop_fake_cur_slist();
446 db_info
.true_side
= 0;
447 __push_fake_cur_slist();
448 run_sql(db_compare_callback
,
449 "select return, type, parameter, key, value from return_states where %s",
451 false_states
= __pop_fake_cur_slist();
453 FOR_EACH_PTR(true_states
, sm
) {
454 __set_true_false_sm(sm
, NULL
);
455 } END_FOR_EACH_PTR(sm
);
456 FOR_EACH_PTR(false_states
, sm
) {
457 __set_true_false_sm(NULL
, sm
);
458 } END_FOR_EACH_PTR(sm
);
460 free_slist(&true_states
);
461 free_slist(&false_states
);
466 void function_comparison(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
468 if (call_implies_callbacks(comparison
, expr
, sval
, left
))
470 compare_db_implies_callbacks(comparison
, expr
, sval
, left
);
471 compare_db_return_states_callbacks(comparison
, expr
, sval
, left
);
474 static int db_assign_callback(void *unused
, int argc
, char **argv
, char **azColName
)
476 struct range_list
*ret_range
;
479 struct return_implies_callback
*tmp
;
480 struct state_list
*slist
;
485 parse_value_ranges_type(get_type(db_info
.expr
->right
), argv
[0], &ret_range
);
486 type
= atoi(argv
[1]);
487 param
= atoi(argv
[2]);
491 __push_fake_cur_slist();
492 FOR_EACH_PTR(db_implies_list
, tmp
) {
493 if (tmp
->type
== type
)
494 tmp
->callback(db_info
.expr
->right
, param
, key
, value
);
495 } END_FOR_EACH_PTR(tmp
);
496 ret_range
= cast_rl(get_type(db_info
.expr
->left
), ret_range
);
497 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_range_list(ret_range
));
498 slist
= __pop_fake_cur_slist();
500 merge_slist(&db_info
.slist
, slist
);
505 static int db_return_implies_assign(struct expression
*expr
)
508 static char sql_filter
[1024];
509 static struct sm_state
*sm
;
512 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
515 sym
= expr
->right
->fn
->symbol
;
519 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
520 snprintf(sql_filter
, 1024,
521 "file = '%s' and function = '%s' and static = '1';",
522 get_filename(), sym
->ident
->name
);
524 snprintf(sql_filter
, 1024,
525 "function = '%s' and static = '0';", sym
->ident
->name
);
529 db_info
.slist
= NULL
;
530 run_sql(db_assign_callback
,
531 "select return, type, parameter, key, value from return_implies where %s",
534 FOR_EACH_PTR(db_info
.slist
, sm
) {
537 } END_FOR_EACH_PTR(sm
);
542 static int prev_return_id
;
543 static int db_assign_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
545 struct range_list
*ret_range
;
548 struct return_implies_callback
*tmp
;
549 struct state_list
*slist
;
555 return_id
= atoi(argv
[0]);
556 parse_value_ranges_type(get_type(db_info
.expr
->right
), argv
[1], &ret_range
);
558 ret_range
= whole_range_list(cur_func_return_type());
559 type
= atoi(argv
[2]);
560 param
= atoi(argv
[3]);
564 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
565 slist
= __pop_fake_cur_slist();
566 merge_slist(&db_info
.slist
, slist
);
567 __push_fake_cur_slist();
569 prev_return_id
= return_id
;
571 FOR_EACH_PTR(db_return_states_list
, tmp
) {
572 if (tmp
->type
== type
)
573 tmp
->callback(db_info
.expr
, param
, key
, value
);
574 } END_FOR_EACH_PTR(tmp
);
575 ret_range
= cast_rl(get_type(db_info
.expr
->left
), ret_range
);
576 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_range_list(ret_range
));
581 static int db_return_states_assign(struct expression
*expr
)
583 struct expression
*right
;
586 struct state_list
*slist
;
587 static char sql_filter
[1024];
590 right
= strip_expr(expr
->right
);
591 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
594 sym
= right
->fn
->symbol
;
598 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
599 snprintf(sql_filter
, 1024,
600 "file = '%s' and function = '%s' and static = '1';",
601 get_filename(), sym
->ident
->name
);
603 snprintf(sql_filter
, 1024,
604 "function = '%s' and static = '0';", sym
->ident
->name
);
609 db_info
.slist
= NULL
;
610 __push_fake_cur_slist();
611 run_sql(db_assign_return_states_callback
,
612 "select return_id, return, type, parameter, key, value from return_states where %s",
614 slist
= __pop_fake_cur_slist();
615 merge_slist(&db_info
.slist
, slist
);
617 FOR_EACH_PTR(db_info
.slist
, sm
) {
620 } END_FOR_EACH_PTR(sm
);
625 static int handle_implied_return(struct expression
*expr
)
627 struct range_list
*rl
;
629 if (!get_implied_return(expr
->right
, &rl
))
631 rl
= cast_rl(get_type(expr
->left
), rl
);
632 set_extra_expr_mod(expr
->left
, alloc_estate_range_list(rl
));
636 static void match_assign_call(struct expression
*expr
)
638 struct call_back_list
*call_backs
;
640 struct expression
*right
;
643 right
= strip_expr(expr
->right
);
644 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
) {
645 set_extra_expr_mod(expr
->left
, extra_undefined(get_type(expr
->left
)));
648 fn
= right
->fn
->symbol
->ident
->name
;
651 * some of these conflict (they try to set smatch extra twice), so we
652 * call them in order from least important to most important.
655 call_backs
= search_callback(func_hash
, (char *)fn
);
656 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
658 handled
|= db_return_states_assign(expr
);
659 handled
|= db_return_implies_assign(expr
);
660 handled
|= assign_ranged_funcs(fn
, expr
, call_backs
);
661 handled
|= handle_implied_return(expr
);
664 set_extra_expr_mod(expr
->left
, extra_undefined(get_type(expr
->left
)));
667 static int db_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
669 struct range_list
*ret_range
;
672 struct return_implies_callback
*tmp
;
673 struct state_list
*slist
;
679 return_id
= atoi(argv
[0]);
680 parse_value_ranges_type(get_type(db_info
.expr
), argv
[1], &ret_range
);
681 type
= atoi(argv
[2]);
682 param
= atoi(argv
[3]);
686 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
687 slist
= __pop_fake_cur_slist();
688 merge_slist(&db_info
.slist
, slist
);
689 __push_fake_cur_slist();
691 prev_return_id
= return_id
;
693 FOR_EACH_PTR(db_return_states_list
, tmp
) {
694 if (tmp
->type
== type
)
695 tmp
->callback(db_info
.expr
, param
, key
, value
);
696 } END_FOR_EACH_PTR(tmp
);
701 static void db_return_states(struct expression
*expr
)
705 struct state_list
*slist
;
706 static char sql_filter
[1024];
708 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
711 sym
= expr
->fn
->symbol
;
715 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
716 snprintf(sql_filter
, 1024,
717 "file = '%s' and function = '%s' and static = '1';",
718 get_filename(), sym
->ident
->name
);
720 snprintf(sql_filter
, 1024,
721 "function = '%s' and static = '0';", sym
->ident
->name
);
726 db_info
.slist
= NULL
;
727 __push_fake_cur_slist();
728 run_sql(db_return_states_callback
,
729 "select return_id, return, type, parameter, key, value from return_states where %s",
731 slist
= __pop_fake_cur_slist();
732 merge_slist(&db_info
.slist
, slist
);
734 FOR_EACH_PTR(db_info
.slist
, sm
) {
736 } END_FOR_EACH_PTR(sm
);
739 static int is_assigned_call(struct expression
*expr
)
741 struct expression
*tmp
;
743 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
744 if (tmp
->type
== EXPR_ASSIGNMENT
&& strip_expr(tmp
->right
) == expr
)
746 if (tmp
->pos
.line
< expr
->pos
.line
)
748 } END_FOR_EACH_PTR_REVERSE(tmp
);
752 static void db_return_states_call(struct expression
*expr
)
754 if (is_assigned_call(expr
))
756 db_return_states(expr
);
759 static void match_function_call(struct expression
*expr
)
761 struct call_back_list
*call_backs
;
763 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
765 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
767 call_call_backs(call_backs
, REGULAR_CALL
,
768 expr
->fn
->symbol
->ident
->name
, expr
);
769 db_return_states_call(expr
);
772 static void match_macro_assign(struct expression
*expr
)
774 struct call_back_list
*call_backs
;
776 struct expression
*right
;
778 right
= strip_expr(expr
->right
);
779 macro
= get_macro_name(right
->pos
);
780 call_backs
= search_callback(func_hash
, (char *)macro
);
783 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
784 call_call_backs(call_backs
, MACRO_ASSIGN_EXTRA
, macro
, expr
);
787 int get_implied_return(struct expression
*expr
, struct range_list
**rl
)
789 struct call_back_list
*call_backs
;
790 struct fcall_back
*tmp
;
796 expr
= strip_expr(expr
);
797 fn
= get_variable_from_expr(expr
->fn
, NULL
);
801 call_backs
= search_callback(func_hash
, fn
);
803 FOR_EACH_PTR(call_backs
, tmp
) {
804 if (tmp
->type
== IMPLIED_RETURN
) {
805 (tmp
->u
.implied_return
)(expr
, tmp
->info
, rl
);
808 } END_FOR_EACH_PTR(tmp
);
815 void create_function_hook_hash(void)
817 func_hash
= create_function_hashtable(5000);
820 void register_function_hooks(int id
)
822 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
823 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
824 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);