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_return_states_list
;
60 typedef void (void_fn
)(void);
61 DECLARE_PTR_LIST(void_fn_list
, void_fn
*);
62 static struct void_fn_list
*return_states_before
;
63 static struct void_fn_list
*return_states_after
;
65 static struct fcall_back
*alloc_fcall_back(int type
, void *call_back
,
68 struct fcall_back
*cb
;
70 cb
= __alloc_fcall_back(0);
72 cb
->u
.call_back
= call_back
;
77 void add_function_hook(const char *look_for
, func_hook
*call_back
, void *info
)
79 struct fcall_back
*cb
;
81 cb
= alloc_fcall_back(REGULAR_CALL
, call_back
, info
);
82 add_callback(func_hash
, look_for
, cb
);
85 void add_function_assign_hook(const char *look_for
, func_hook
*call_back
,
88 struct fcall_back
*cb
;
90 cb
= alloc_fcall_back(ASSIGN_CALL
, call_back
, info
);
91 add_callback(func_hash
, look_for
, cb
);
94 void add_implied_return_hook(const char *look_for
,
95 implied_return_hook
*call_back
,
98 struct fcall_back
*cb
;
100 cb
= alloc_fcall_back(IMPLIED_RETURN
, call_back
, info
);
101 add_callback(func_hash
, look_for
, cb
);
104 void add_macro_assign_hook(const char *look_for
, func_hook
*call_back
,
107 struct fcall_back
*cb
;
109 cb
= alloc_fcall_back(MACRO_ASSIGN
, call_back
, info
);
110 add_callback(func_hash
, look_for
, cb
);
113 void add_macro_assign_hook_extra(const char *look_for
, func_hook
*call_back
,
116 struct fcall_back
*cb
;
118 cb
= alloc_fcall_back(MACRO_ASSIGN_EXTRA
, call_back
, info
);
119 add_callback(func_hash
, look_for
, cb
);
122 void return_implies_state(const char *look_for
, long long start
, long long end
,
123 implication_hook
*call_back
, void *info
)
125 struct fcall_back
*cb
;
127 cb
= alloc_fcall_back(RANGED_CALL
, call_back
, info
);
128 cb
->range
= alloc_range_perm(ll_to_sval(start
), ll_to_sval(end
));
129 add_callback(func_hash
, look_for
, cb
);
132 void add_db_return_states_callback(int type
, return_implies_hook
*callback
)
134 struct return_implies_callback
*cb
= __alloc_return_implies_callback(0);
137 cb
->callback
= callback
;
138 add_ptr_list(&db_return_states_list
, cb
);
141 void add_db_return_states_before(void_fn
*fn
)
143 void_fn
**p
= malloc(sizeof(void_fn
*));
145 add_ptr_list(&return_states_before
, p
);
148 void add_db_return_states_after(void_fn
*fn
)
150 void_fn
**p
= malloc(sizeof(void_fn
*));
152 add_ptr_list(&return_states_after
, p
);
155 static void call_return_states_before_hooks(void)
159 FOR_EACH_PTR(return_states_before
, fn
) {
161 } END_FOR_EACH_PTR(fn
);
164 static void call_return_states_after_hooks(void)
168 FOR_EACH_PTR(return_states_after
, fn
) {
170 } END_FOR_EACH_PTR(fn
);
173 static int call_call_backs(struct call_back_list
*list
, int type
,
174 const char *fn
, struct expression
*expr
)
176 struct fcall_back
*tmp
;
179 FOR_EACH_PTR(list
, tmp
) {
180 if (tmp
->type
== type
) {
181 (tmp
->u
.call_back
)(fn
, expr
, tmp
->info
);
184 } END_FOR_EACH_PTR(tmp
);
189 static void call_ranged_call_backs(struct call_back_list
*list
,
190 const char *fn
, struct expression
*call_expr
,
191 struct expression
*assign_expr
)
193 struct fcall_back
*tmp
;
195 FOR_EACH_PTR(list
, tmp
) {
196 (tmp
->u
.ranged
)(fn
, call_expr
, assign_expr
, tmp
->info
);
197 } END_FOR_EACH_PTR(tmp
);
200 static struct call_back_list
*get_same_ranged_call_backs(struct call_back_list
*list
,
201 struct data_range
*drange
)
203 struct call_back_list
*ret
= NULL
;
204 struct fcall_back
*tmp
;
206 FOR_EACH_PTR(list
, tmp
) {
207 if (tmp
->type
!= RANGED_CALL
)
209 if (ranges_equiv(tmp
->range
, drange
))
210 add_ptr_list(&ret
, tmp
);
211 } END_FOR_EACH_PTR(tmp
);
215 static int in_list_exact_sval(struct range_list
*list
, struct data_range
*drange
)
217 struct data_range
*tmp
;
219 FOR_EACH_PTR(list
, tmp
) {
220 if (ranges_equiv(tmp
, drange
))
222 } END_FOR_EACH_PTR(tmp
);
226 static int assign_ranged_funcs(const char *fn
, struct expression
*expr
,
227 struct call_back_list
*call_backs
)
229 struct fcall_back
*tmp
;
233 struct smatch_state
*estate
;
234 struct state_list
*tmp_slist
;
235 struct state_list
*final_states
= NULL
;
236 struct range_list
*handled_ranges
= NULL
;
237 struct call_back_list
*same_range_call_backs
= NULL
;
243 var_name
= expr_to_str_sym(expr
->left
, &sym
);
244 if (!var_name
|| !sym
)
247 FOR_EACH_PTR(call_backs
, tmp
) {
248 if (tmp
->type
!= RANGED_CALL
)
251 if (in_list_exact_sval(handled_ranges
, tmp
->range
))
253 __push_fake_cur_slist();
254 tack_on(&handled_ranges
, tmp
->range
);
256 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp
->range
);
257 call_ranged_call_backs(same_range_call_backs
, fn
, expr
->right
, expr
);
258 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
260 estate
= alloc_estate_range(tmp
->range
->min
, tmp
->range
->max
);
261 set_extra_mod(var_name
, sym
, estate
);
263 tmp_slist
= __pop_fake_cur_slist();
264 merge_slist(&final_states
, tmp_slist
);
265 free_slist(&tmp_slist
);
267 } END_FOR_EACH_PTR(tmp
);
269 FOR_EACH_PTR(final_states
, sm
) {
271 } END_FOR_EACH_PTR(sm
);
273 free_slist(&final_states
);
275 free_string(var_name
);
279 static int call_implies_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
281 struct call_back_list
*call_backs
;
282 struct fcall_back
*tmp
;
284 struct data_range
*value_range
;
285 struct state_list
*true_states
= NULL
;
286 struct state_list
*false_states
= NULL
;
287 struct state_list
*tmp_slist
;
290 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
292 fn
= expr
->fn
->symbol
->ident
->name
;
293 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
296 value_range
= alloc_range(sval
, sval
);
298 /* set true states */
299 __push_fake_cur_slist();
300 FOR_EACH_PTR(call_backs
, tmp
) {
301 if (tmp
->type
!= RANGED_CALL
)
303 if (!true_comparison_range_LR(comparison
, tmp
->range
, value_range
, left
))
305 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
306 } END_FOR_EACH_PTR(tmp
);
307 tmp_slist
= __pop_fake_cur_slist();
308 merge_slist(&true_states
, tmp_slist
);
309 free_slist(&tmp_slist
);
311 /* set false states */
312 __push_fake_cur_slist();
313 FOR_EACH_PTR(call_backs
, tmp
) {
314 if (tmp
->type
!= RANGED_CALL
)
316 if (!false_comparison_range_LR(comparison
, tmp
->range
, value_range
, left
))
318 (tmp
->u
.ranged
)(fn
, expr
, NULL
, tmp
->info
);
319 } END_FOR_EACH_PTR(tmp
);
320 tmp_slist
= __pop_fake_cur_slist();
321 merge_slist(&false_states
, tmp_slist
);
322 free_slist(&tmp_slist
);
324 FOR_EACH_PTR(true_states
, sm
) {
325 __set_true_false_sm(sm
, NULL
);
326 } END_FOR_EACH_PTR(sm
);
327 FOR_EACH_PTR(false_states
, sm
) {
328 __set_true_false_sm(NULL
, sm
);
329 } END_FOR_EACH_PTR(sm
);
331 free_slist(&true_states
);
332 free_slist(&false_states
);
336 struct db_callback_info
{
339 struct expression
*expr
;
340 struct range_list
*rl
;
342 struct state_list
*slist
;
343 struct db_implies_list
*callbacks
;
345 static struct db_callback_info db_info
;
346 static int db_compare_callback(void *unused
, int argc
, char **argv
, char **azColName
)
348 struct range_list
*ret_range
;
351 struct return_implies_callback
*tmp
;
356 str_to_rl(get_type(db_info
.expr
), argv
[0], &ret_range
);
357 type
= atoi(argv
[1]);
358 param
= atoi(argv
[2]);
362 if (db_info
.true_side
) {
363 if (!possibly_true_rl_LR(db_info
.comparison
,
364 ret_range
, db_info
.rl
,
368 if (!possibly_false_rl_LR(db_info
.comparison
,
369 ret_range
, db_info
.rl
,
374 FOR_EACH_PTR(db_info
.callbacks
, tmp
) {
375 if (tmp
->type
== type
)
376 tmp
->callback(db_info
.expr
, param
, key
, value
);
377 } END_FOR_EACH_PTR(tmp
);
381 void compare_db_return_states_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
384 static char sql_filter
[1024];
385 struct state_list
*true_states
;
386 struct state_list
*false_states
;
389 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
392 sym
= expr
->fn
->symbol
;
396 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
397 snprintf(sql_filter
, 1024,
398 "file = '%s' and function = '%s' and static = '1';",
399 get_filename(), sym
->ident
->name
);
401 snprintf(sql_filter
, 1024,
402 "function = '%s' and static = '0';", sym
->ident
->name
);
405 db_info
.comparison
= comparison
;
407 db_info
.rl
= alloc_rl(sval
, sval
);
409 db_info
.callbacks
= db_return_states_list
;
411 call_return_states_before_hooks();
413 db_info
.true_side
= 1;
414 __push_fake_cur_slist();
415 run_sql(db_compare_callback
,
416 "select return, type, parameter, key, value from return_states where %s",
418 true_states
= __pop_fake_cur_slist();
420 db_info
.true_side
= 0;
421 __push_fake_cur_slist();
422 run_sql(db_compare_callback
,
423 "select return, type, parameter, key, value from return_states where %s",
425 false_states
= __pop_fake_cur_slist();
427 FOR_EACH_PTR(true_states
, sm
) {
428 __set_true_false_sm(sm
, NULL
);
429 } END_FOR_EACH_PTR(sm
);
430 FOR_EACH_PTR(false_states
, sm
) {
431 __set_true_false_sm(NULL
, sm
);
432 } END_FOR_EACH_PTR(sm
);
434 call_return_states_after_hooks();
436 free_slist(&true_states
);
437 free_slist(&false_states
);
442 void function_comparison(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
444 if (call_implies_callbacks(comparison
, expr
, sval
, left
))
446 compare_db_return_states_callbacks(comparison
, expr
, sval
, left
);
449 static int prev_return_id
;
450 static int db_assign_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
452 struct range_list
*ret_range
;
455 struct return_implies_callback
*tmp
;
456 struct state_list
*slist
;
462 return_id
= atoi(argv
[0]);
463 str_to_rl(get_type(db_info
.expr
->right
), argv
[1], &ret_range
);
465 ret_range
= alloc_whole_rl(cur_func_return_type());
466 type
= atoi(argv
[2]);
467 param
= atoi(argv
[3]);
471 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
472 slist
= __pop_fake_cur_slist();
473 merge_slist(&db_info
.slist
, slist
);
474 __push_fake_cur_slist();
476 prev_return_id
= return_id
;
478 FOR_EACH_PTR(db_return_states_list
, tmp
) {
479 if (tmp
->type
== type
)
480 tmp
->callback(db_info
.expr
, param
, key
, value
);
481 } END_FOR_EACH_PTR(tmp
);
482 ret_range
= cast_rl(get_type(db_info
.expr
->left
), ret_range
);
483 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_rl(ret_range
));
488 static int db_return_states_assign(struct expression
*expr
)
490 struct expression
*right
;
493 struct state_list
*slist
;
494 static char sql_filter
[1024];
497 right
= strip_expr(expr
->right
);
498 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
501 sym
= right
->fn
->symbol
;
505 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
506 snprintf(sql_filter
, 1024,
507 "file = '%s' and function = '%s' and static = '1';",
508 get_filename(), sym
->ident
->name
);
510 snprintf(sql_filter
, 1024,
511 "function = '%s' and static = '0';", sym
->ident
->name
);
516 db_info
.slist
= NULL
;
518 call_return_states_before_hooks();
520 __push_fake_cur_slist();
521 run_sql(db_assign_return_states_callback
,
522 "select return_id, return, type, parameter, key, value from return_states where %s",
524 slist
= __pop_fake_cur_slist();
525 merge_slist(&db_info
.slist
, slist
);
527 FOR_EACH_PTR(db_info
.slist
, sm
) {
530 } END_FOR_EACH_PTR(sm
);
532 call_return_states_after_hooks();
537 static int handle_implied_return(struct expression
*expr
)
539 struct range_list
*rl
;
541 if (!get_implied_return(expr
->right
, &rl
))
543 rl
= cast_rl(get_type(expr
->left
), rl
);
544 set_extra_expr_mod(expr
->left
, alloc_estate_rl(rl
));
548 static void match_assign_call(struct expression
*expr
)
550 struct call_back_list
*call_backs
;
552 struct expression
*right
;
555 right
= strip_expr(expr
->right
);
556 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
) {
557 set_extra_expr_mod(expr
->left
, alloc_estate_whole(get_type(expr
->left
)));
560 fn
= right
->fn
->symbol
->ident
->name
;
563 * some of these conflict (they try to set smatch extra twice), so we
564 * call them in order from least important to most important.
567 call_backs
= search_callback(func_hash
, (char *)fn
);
568 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
570 handled
|= db_return_states_assign(expr
);
571 handled
|= assign_ranged_funcs(fn
, expr
, call_backs
);
572 handled
|= handle_implied_return(expr
);
575 struct range_list
*rl
;
577 if (!get_implied_rl(expr
->right
, &rl
))
578 rl
= alloc_whole_rl(get_type(expr
->right
));
579 rl
= cast_rl(get_type(expr
->left
), rl
);
580 set_extra_expr_mod(expr
->left
, alloc_estate_rl(rl
));
584 static int db_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
586 struct range_list
*ret_range
;
589 struct return_implies_callback
*tmp
;
590 struct state_list
*slist
;
596 return_id
= atoi(argv
[0]);
597 str_to_rl(get_type(db_info
.expr
), argv
[1], &ret_range
);
598 type
= atoi(argv
[2]);
599 param
= atoi(argv
[3]);
603 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
604 slist
= __pop_fake_cur_slist();
605 merge_slist(&db_info
.slist
, slist
);
606 __push_fake_cur_slist();
609 prev_return_id
= return_id
;
611 FOR_EACH_PTR(db_return_states_list
, tmp
) {
612 if (tmp
->type
== type
)
613 tmp
->callback(db_info
.expr
, param
, key
, value
);
614 } END_FOR_EACH_PTR(tmp
);
619 static void db_return_states(struct expression
*expr
)
623 struct state_list
*slist
;
624 static char sql_filter
[1024];
626 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
629 sym
= expr
->fn
->symbol
;
633 if (sym
->ctype
.modifiers
& MOD_STATIC
) {
634 snprintf(sql_filter
, 1024,
635 "file = '%s' and function = '%s' and static = '1';",
636 get_filename(), sym
->ident
->name
);
638 snprintf(sql_filter
, 1024,
639 "function = '%s' and static = '0';", sym
->ident
->name
);
644 db_info
.slist
= NULL
;
646 call_return_states_before_hooks();
648 __push_fake_cur_slist();
650 run_sql(db_return_states_callback
,
651 "select return_id, return, type, parameter, key, value from return_states where %s",
653 slist
= __pop_fake_cur_slist();
654 merge_slist(&db_info
.slist
, slist
);
656 FOR_EACH_PTR(db_info
.slist
, sm
) {
658 } END_FOR_EACH_PTR(sm
);
660 call_return_states_after_hooks();
663 static int is_assigned_call(struct expression
*expr
)
665 struct expression
*tmp
;
667 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
668 if (tmp
->type
== EXPR_ASSIGNMENT
&& strip_expr(tmp
->right
) == expr
)
670 if (tmp
->pos
.line
< expr
->pos
.line
)
672 } END_FOR_EACH_PTR_REVERSE(tmp
);
676 static void db_return_states_call(struct expression
*expr
)
678 if (is_assigned_call(expr
))
680 db_return_states(expr
);
683 static void match_function_call(struct expression
*expr
)
685 struct call_back_list
*call_backs
;
687 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
689 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
691 call_call_backs(call_backs
, REGULAR_CALL
,
692 expr
->fn
->symbol
->ident
->name
, expr
);
693 db_return_states_call(expr
);
696 static void match_macro_assign(struct expression
*expr
)
698 struct call_back_list
*call_backs
;
700 struct expression
*right
;
702 right
= strip_expr(expr
->right
);
703 macro
= get_macro_name(right
->pos
);
704 call_backs
= search_callback(func_hash
, (char *)macro
);
707 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
708 call_call_backs(call_backs
, MACRO_ASSIGN_EXTRA
, macro
, expr
);
711 int get_implied_return(struct expression
*expr
, struct range_list
**rl
)
713 struct call_back_list
*call_backs
;
714 struct fcall_back
*tmp
;
720 expr
= strip_expr(expr
);
721 fn
= expr_to_str(expr
->fn
);
725 call_backs
= search_callback(func_hash
, fn
);
727 FOR_EACH_PTR(call_backs
, tmp
) {
728 if (tmp
->type
== IMPLIED_RETURN
) {
729 (tmp
->u
.implied_return
)(expr
, tmp
->info
, rl
);
732 } END_FOR_EACH_PTR(tmp
);
739 void create_function_hook_hash(void)
741 func_hash
= create_function_hashtable(5000);
744 void register_function_hooks(int id
)
746 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
747 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
748 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);