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(start
, 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_sval
*drange
)
176 struct call_back_list
*ret
= NULL
;
177 struct fcall_back
*tmp
;
179 FOR_EACH_PTR(list
, tmp
) {
180 struct data_range_sval
*range_tmp
;
182 if (tmp
->type
!= RANGED_CALL
)
184 range_tmp
= drange_to_drange_sval(tmp
->range
);
185 if (ranges_equiv_sval(range_tmp
, drange
))
186 add_ptr_list(&ret
, tmp
);
187 } END_FOR_EACH_PTR(tmp
);
191 static int in_list_exact_sval(struct range_list_sval
*list
, struct data_range_sval
*drange
)
193 struct data_range_sval
*tmp
;
195 FOR_EACH_PTR(list
, tmp
) {
196 if (ranges_equiv_sval(tmp
, drange
))
198 } END_FOR_EACH_PTR(tmp
);
202 static int assign_ranged_funcs(const char *fn
, struct expression
*expr
,
203 struct call_back_list
*call_backs
)
205 struct fcall_back
*tmp
;
209 struct smatch_state
*estate
;
210 struct state_list
*tmp_slist
;
211 struct state_list
*final_states
= NULL
;
212 struct range_list_sval
*handled_ranges
= NULL
;
213 struct call_back_list
*same_range_call_backs
= NULL
;
219 var_name
= get_variable_from_expr(expr
->left
, &sym
);
220 if (!var_name
|| !sym
)
223 FOR_EACH_PTR(call_backs
, tmp
) {
224 struct data_range_sval
*tmp_dr_sval
;
226 if (tmp
->type
!= RANGED_CALL
)
228 tmp_dr_sval
= drange_to_drange_sval(tmp
->range
);
230 if (in_list_exact_sval(handled_ranges
, tmp_dr_sval
))
232 __push_fake_cur_slist();
233 tack_on_sval(&handled_ranges
, tmp_dr_sval
);
235 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp_dr_sval
);
236 call_ranged_call_backs(same_range_call_backs
, fn
, expr
->right
, expr
);
237 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
239 estate
= alloc_estate_range(tmp
->range
->min
, tmp
->range
->max
);
240 set_extra_mod(var_name
, sym
, estate
);
242 tmp_slist
= __pop_fake_cur_slist();
243 merge_slist(&final_states
, tmp_slist
);
244 free_slist(&tmp_slist
);
246 } END_FOR_EACH_PTR(tmp
);
248 FOR_EACH_PTR(final_states
, sm
) {
250 } END_FOR_EACH_PTR(sm
);
252 free_slist(&final_states
);
254 free_string(var_name
);
258 int call_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
260 struct call_back_list
*call_backs
;
261 struct fcall_back
*tmp
;
263 struct data_range_sval
*value_range
;
264 struct state_list
*true_states
= NULL
;
265 struct state_list
*false_states
= NULL
;
266 struct state_list
*tmp_slist
;
269 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
271 fn
= expr
->fn
->symbol
->ident
->name
;
272 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
275 value_range
= alloc_range_sval(ll_to_sval(value
), ll_to_sval(value
));
277 /* set true states */
278 __push_fake_cur_slist();
279 FOR_EACH_PTR(call_backs
, tmp
) {
280 if (tmp
->type
!= RANGED_CALL
)
282 if (!true_comparison_range_lr_sval(comparison
, drange_to_drange_sval(tmp
->range
), value_range
, left
))
284 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
285 } END_FOR_EACH_PTR(tmp
);
286 tmp_slist
= __pop_fake_cur_slist();
287 merge_slist(&true_states
, tmp_slist
);
288 free_slist(&tmp_slist
);
290 /* set false states */
291 __push_fake_cur_slist();
292 FOR_EACH_PTR(call_backs
, tmp
) {
293 if (tmp
->type
!= RANGED_CALL
)
295 if (!false_comparison_range_lr_sval(comparison
, drange_to_drange_sval(tmp
->range
), value_range
, left
))
297 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
298 } END_FOR_EACH_PTR(tmp
);
299 tmp_slist
= __pop_fake_cur_slist();
300 merge_slist(&false_states
, tmp_slist
);
301 free_slist(&tmp_slist
);
303 FOR_EACH_PTR(true_states
, sm
) {
304 __set_true_false_sm(sm
, NULL
);
305 } END_FOR_EACH_PTR(sm
);
306 FOR_EACH_PTR(false_states
, sm
) {
307 __set_true_false_sm(NULL
, sm
);
308 } END_FOR_EACH_PTR(sm
);
310 free_slist(&true_states
);
311 free_slist(&false_states
);
315 struct db_callback_info
{
318 struct expression
*expr
;
319 struct range_list_sval
*rl
;
321 struct state_list
*slist
;
322 struct db_implies_list
*callbacks
;
324 static struct db_callback_info db_info
;
325 static int db_compare_callback(void *unused
, int argc
, char **argv
, char **azColName
)
327 struct range_list_sval
*ret_range
;
330 struct return_implies_callback
*tmp
;
335 get_value_ranges_sval(argv
[0], &ret_range
);
336 type
= atoi(argv
[1]);
337 param
= atoi(argv
[2]);
341 if (db_info
.true_side
) {
342 if (!possibly_true_range_lists_rl_sval(db_info
.comparison
,
343 ret_range
, db_info
.rl
,
347 if (!possibly_false_range_lists_rl_sval(db_info
.comparison
,
348 ret_range
, db_info
.rl
,
353 FOR_EACH_PTR(db_info
.callbacks
, tmp
) {
354 if (tmp
->type
== type
)
355 tmp
->callback(db_info
.expr
, param
, key
, value
);
356 } END_FOR_EACH_PTR(tmp
);
360 void compare_db_implies_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
363 static char sql_filter
[1024];
364 struct state_list
*true_states
;
365 struct state_list
*false_states
;
368 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
371 sym
= expr
->fn
->symbol
;
375 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
376 snprintf(sql_filter
, 1024,
377 "file = '%s' and function = '%s' and static = '1';",
378 get_filename(), sym
->ident
->name
);
380 snprintf(sql_filter
, 1024,
381 "function = '%s' and static = '0';", sym
->ident
->name
);
384 db_info
.comparison
= comparison
;
386 db_info
.rl
= range_list_to_sval(alloc_range_list(value
, value
));
388 db_info
.callbacks
= db_implies_list
;
390 db_info
.true_side
= 1;
391 __push_fake_cur_slist();
392 run_sql(db_compare_callback
,
393 "select return, type, parameter, key, value from return_implies where %s",
395 true_states
= __pop_fake_cur_slist();
397 db_info
.true_side
= 0;
398 __push_fake_cur_slist();
399 run_sql(db_compare_callback
,
400 "select return, type, parameter, key, value from return_implies where %s",
402 false_states
= __pop_fake_cur_slist();
404 FOR_EACH_PTR(true_states
, sm
) {
405 __set_true_false_sm(sm
, NULL
);
406 } END_FOR_EACH_PTR(sm
);
407 FOR_EACH_PTR(false_states
, sm
) {
408 __set_true_false_sm(NULL
, sm
);
409 } END_FOR_EACH_PTR(sm
);
411 free_slist(&true_states
);
412 free_slist(&false_states
);
415 void compare_db_return_states_callbacks(int comparison
, struct expression
*expr
, long long value
, int left
)
418 static char sql_filter
[1024];
419 struct state_list
*true_states
;
420 struct state_list
*false_states
;
423 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
426 sym
= expr
->fn
->symbol
;
430 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
431 snprintf(sql_filter
, 1024,
432 "file = '%s' and function = '%s' and static = '1';",
433 get_filename(), sym
->ident
->name
);
435 snprintf(sql_filter
, 1024,
436 "function = '%s' and static = '0';", sym
->ident
->name
);
439 db_info
.comparison
= comparison
;
441 db_info
.rl
= range_list_to_sval(alloc_range_list(value
, value
));
443 db_info
.callbacks
= db_return_states_list
;
445 db_info
.true_side
= 1;
446 __push_fake_cur_slist();
447 run_sql(db_compare_callback
,
448 "select return, type, parameter, key, value from return_states where %s",
450 true_states
= __pop_fake_cur_slist();
452 db_info
.true_side
= 0;
453 __push_fake_cur_slist();
454 run_sql(db_compare_callback
,
455 "select return, type, parameter, key, value from return_states where %s",
457 false_states
= __pop_fake_cur_slist();
459 FOR_EACH_PTR(true_states
, sm
) {
460 __set_true_false_sm(sm
, NULL
);
461 } END_FOR_EACH_PTR(sm
);
462 FOR_EACH_PTR(false_states
, sm
) {
463 __set_true_false_sm(NULL
, sm
);
464 } END_FOR_EACH_PTR(sm
);
466 free_slist(&true_states
);
467 free_slist(&false_states
);
472 void function_comparison(int comparison
, struct expression
*expr
,
473 long long value
, int left
)
475 if (call_implies_callbacks(comparison
, expr
, value
, left
))
477 compare_db_implies_callbacks(comparison
, expr
, value
, left
);
478 compare_db_return_states_callbacks(comparison
, expr
, value
, left
);
481 static int db_assign_callback(void *unused
, int argc
, char **argv
, char **azColName
)
483 struct range_list_sval
*ret_range
;
486 struct return_implies_callback
*tmp
;
487 struct state_list
*slist
;
492 get_value_ranges_sval(argv
[0], &ret_range
);
493 type
= atoi(argv
[1]);
494 param
= atoi(argv
[2]);
498 __push_fake_cur_slist();
499 FOR_EACH_PTR(db_implies_list
, tmp
) {
500 if (tmp
->type
== type
)
501 tmp
->callback(db_info
.expr
->right
, param
, key
, value
);
502 } END_FOR_EACH_PTR(tmp
);
503 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_range_list(rl_sval_to_rl(ret_range
)));
504 slist
= __pop_fake_cur_slist();
506 merge_slist(&db_info
.slist
, slist
);
511 static int db_return_implies_assign(struct expression
*expr
)
514 static char sql_filter
[1024];
515 static struct sm_state
*sm
;
518 if (expr
->right
->fn
->type
!= EXPR_SYMBOL
|| !expr
->right
->fn
->symbol
)
521 sym
= expr
->right
->fn
->symbol
;
525 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
526 snprintf(sql_filter
, 1024,
527 "file = '%s' and function = '%s' and static = '1';",
528 get_filename(), sym
->ident
->name
);
530 snprintf(sql_filter
, 1024,
531 "function = '%s' and static = '0';", sym
->ident
->name
);
535 db_info
.slist
= NULL
;
536 run_sql(db_assign_callback
,
537 "select return, type, parameter, key, value from return_implies where %s",
540 FOR_EACH_PTR(db_info
.slist
, sm
) {
543 } END_FOR_EACH_PTR(sm
);
548 static int prev_return_id
;
549 static int db_assign_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
551 struct range_list_sval
*ret_range
;
554 struct return_implies_callback
*tmp
;
555 struct state_list
*slist
;
561 return_id
= atoi(argv
[0]);
562 get_value_ranges_sval(argv
[1], &ret_range
);
564 ret_range
= range_list_to_sval(whole_range_list());
565 type
= atoi(argv
[2]);
566 param
= atoi(argv
[3]);
570 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
571 slist
= __pop_fake_cur_slist();
572 merge_slist(&db_info
.slist
, slist
);
573 __push_fake_cur_slist();
575 prev_return_id
= return_id
;
577 FOR_EACH_PTR(db_return_states_list
, tmp
) {
578 if (tmp
->type
== type
)
579 tmp
->callback(db_info
.expr
, param
, key
, value
);
580 } END_FOR_EACH_PTR(tmp
);
581 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_range_list(rl_sval_to_rl(ret_range
)));
586 static int db_return_states_assign(struct expression
*expr
)
588 struct expression
*right
;
591 struct state_list
*slist
;
592 static char sql_filter
[1024];
595 right
= strip_expr(expr
->right
);
596 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
599 sym
= right
->fn
->symbol
;
603 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
604 snprintf(sql_filter
, 1024,
605 "file = '%s' and function = '%s' and static = '1';",
606 get_filename(), sym
->ident
->name
);
608 snprintf(sql_filter
, 1024,
609 "function = '%s' and static = '0';", sym
->ident
->name
);
614 db_info
.slist
= NULL
;
615 __push_fake_cur_slist();
616 run_sql(db_assign_return_states_callback
,
617 "select return_id, return, type, parameter, key, value from return_states where %s",
619 slist
= __pop_fake_cur_slist();
620 merge_slist(&db_info
.slist
, slist
);
622 FOR_EACH_PTR(db_info
.slist
, sm
) {
625 } END_FOR_EACH_PTR(sm
);
630 static int handle_implied_return(struct expression
*expr
)
632 struct range_list_sval
*rl
;
633 struct range_list
*tmp_no_sval
;
635 if (!get_implied_return_sval(expr
->right
, &rl
))
637 tmp_no_sval
= rl_sval_to_rl(rl
);
638 set_extra_expr_mod(expr
->left
, alloc_estate_range_list(tmp_no_sval
));
642 static void match_assign_call(struct expression
*expr
)
644 struct call_back_list
*call_backs
;
646 struct expression
*right
;
649 right
= strip_expr(expr
->right
);
650 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
) {
651 set_extra_expr_mod(expr
->left
, extra_undefined());
654 fn
= right
->fn
->symbol
->ident
->name
;
657 * some of these conflict (they try to set smatch extra twice), so we
658 * call them in order from least important to most important.
661 call_backs
= search_callback(func_hash
, (char *)fn
);
662 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
664 handled
|= db_return_states_assign(expr
);
665 handled
|= db_return_implies_assign(expr
);
666 handled
|= assign_ranged_funcs(fn
, expr
, call_backs
);
667 handled
|= handle_implied_return(expr
);
670 set_extra_expr_mod(expr
->left
, extra_undefined());
673 static int db_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
675 struct range_list_sval
*ret_range
;
678 struct return_implies_callback
*tmp
;
679 struct state_list
*slist
;
685 return_id
= atoi(argv
[0]);
686 get_value_ranges_sval(argv
[1], &ret_range
);
687 type
= atoi(argv
[2]);
688 param
= atoi(argv
[3]);
692 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
693 slist
= __pop_fake_cur_slist();
694 merge_slist(&db_info
.slist
, slist
);
695 __push_fake_cur_slist();
697 prev_return_id
= return_id
;
699 FOR_EACH_PTR(db_return_states_list
, tmp
) {
700 if (tmp
->type
== type
)
701 tmp
->callback(db_info
.expr
, param
, key
, value
);
702 } END_FOR_EACH_PTR(tmp
);
707 static void db_return_states(struct expression
*expr
)
711 struct state_list
*slist
;
712 static char sql_filter
[1024];
714 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
717 sym
= expr
->fn
->symbol
;
721 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
722 snprintf(sql_filter
, 1024,
723 "file = '%s' and function = '%s' and static = '1';",
724 get_filename(), sym
->ident
->name
);
726 snprintf(sql_filter
, 1024,
727 "function = '%s' and static = '0';", sym
->ident
->name
);
732 db_info
.slist
= NULL
;
733 __push_fake_cur_slist();
734 run_sql(db_return_states_callback
,
735 "select return_id, return, type, parameter, key, value from return_states where %s",
737 slist
= __pop_fake_cur_slist();
738 merge_slist(&db_info
.slist
, slist
);
740 FOR_EACH_PTR(db_info
.slist
, sm
) {
742 } END_FOR_EACH_PTR(sm
);
745 static int is_assigned_call(struct expression
*expr
)
747 struct expression
*tmp
;
749 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
750 if (tmp
->type
== EXPR_ASSIGNMENT
&& strip_expr(tmp
->right
) == expr
)
752 if (tmp
->pos
.line
< expr
->pos
.line
)
754 } END_FOR_EACH_PTR_REVERSE(tmp
);
758 static void db_return_states_call(struct expression
*expr
)
760 if (is_assigned_call(expr
))
762 db_return_states(expr
);
765 static void match_function_call(struct expression
*expr
)
767 struct call_back_list
*call_backs
;
769 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
771 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
773 call_call_backs(call_backs
, REGULAR_CALL
,
774 expr
->fn
->symbol
->ident
->name
, expr
);
775 db_return_states_call(expr
);
778 static void match_macro_assign(struct expression
*expr
)
780 struct call_back_list
*call_backs
;
782 struct expression
*right
;
784 right
= strip_expr(expr
->right
);
785 macro
= get_macro_name(right
->pos
);
786 call_backs
= search_callback(func_hash
, (char *)macro
);
789 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
790 call_call_backs(call_backs
, MACRO_ASSIGN_EXTRA
, macro
, expr
);
793 int get_implied_return_sval(struct expression
*expr
, struct range_list_sval
**rl
)
795 struct call_back_list
*call_backs
;
796 struct fcall_back
*tmp
;
802 expr
= strip_expr(expr
);
803 fn
= get_variable_from_expr(expr
->fn
, NULL
);
807 call_backs
= search_callback(func_hash
, fn
);
809 FOR_EACH_PTR(call_backs
, tmp
) {
810 if (tmp
->type
== IMPLIED_RETURN
) {
811 (tmp
->u
.implied_return
)(expr
, tmp
->info
, rl
);
814 } END_FOR_EACH_PTR(tmp
);
821 void create_function_hook_hash(void)
823 func_hash
= create_function_hashtable(5000);
826 void register_function_hooks(int id
)
828 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
829 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
830 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);