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_var_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(strip_expr(db_info
.expr
)), argv
[0], &ret_range
);
357 ret_range
= cast_rl(get_type(db_info
.expr
), ret_range
);
358 type
= atoi(argv
[1]);
359 param
= atoi(argv
[2]);
363 if (db_info
.true_side
) {
364 if (!possibly_true_rl_LR(db_info
.comparison
,
365 ret_range
, db_info
.rl
,
369 if (!possibly_false_rl_LR(db_info
.comparison
,
370 ret_range
, db_info
.rl
,
375 FOR_EACH_PTR(db_info
.callbacks
, tmp
) {
376 if (tmp
->type
== type
)
377 tmp
->callback(db_info
.expr
, param
, key
, value
);
378 } END_FOR_EACH_PTR(tmp
);
382 void compare_db_return_states_callbacks(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
384 struct state_list
*true_states
;
385 struct state_list
*false_states
;
388 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
391 db_info
.comparison
= comparison
;
393 db_info
.rl
= alloc_rl(sval
, sval
);
395 db_info
.callbacks
= db_return_states_list
;
397 call_return_states_before_hooks();
399 db_info
.true_side
= 1;
400 __push_fake_cur_slist();
401 sql_select_return_states("return, type, parameter, key, value", expr
,
402 db_compare_callback
);
403 true_states
= __pop_fake_cur_slist();
405 db_info
.true_side
= 0;
406 __push_fake_cur_slist();
407 sql_select_return_states("return, type, parameter, key, value", expr
,
408 db_compare_callback
);
409 false_states
= __pop_fake_cur_slist();
411 FOR_EACH_PTR(true_states
, sm
) {
412 __set_true_false_sm(sm
, NULL
);
413 } END_FOR_EACH_PTR(sm
);
414 FOR_EACH_PTR(false_states
, sm
) {
415 __set_true_false_sm(NULL
, sm
);
416 } END_FOR_EACH_PTR(sm
);
418 call_return_states_after_hooks();
420 free_slist(&true_states
);
421 free_slist(&false_states
);
426 void function_comparison(int comparison
, struct expression
*expr
, sval_t sval
, int left
)
428 if (call_implies_callbacks(comparison
, expr
, sval
, left
))
430 compare_db_return_states_callbacks(comparison
, expr
, sval
, left
);
433 static int prev_return_id
;
434 static int db_assign_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
436 struct range_list
*ret_range
;
439 struct return_implies_callback
*tmp
;
440 struct state_list
*slist
;
446 return_id
= atoi(argv
[0]);
447 str_to_rl(get_type(strip_expr(db_info
.expr
->right
)), argv
[1], &ret_range
);
449 ret_range
= alloc_whole_rl(get_type(strip_expr(db_info
.expr
->right
)));
450 ret_range
= cast_rl(get_type(db_info
.expr
->right
), ret_range
);
451 type
= atoi(argv
[2]);
452 param
= atoi(argv
[3]);
456 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
457 slist
= __pop_fake_cur_slist();
458 merge_slist(&db_info
.slist
, slist
);
459 __push_fake_cur_slist();
461 prev_return_id
= return_id
;
463 FOR_EACH_PTR(db_return_states_list
, tmp
) {
464 if (tmp
->type
== type
)
465 tmp
->callback(db_info
.expr
, param
, key
, value
);
466 } END_FOR_EACH_PTR(tmp
);
467 ret_range
= cast_rl(get_type(db_info
.expr
->left
), ret_range
);
468 set_extra_expr_mod(db_info
.expr
->left
, alloc_estate_rl(ret_range
));
473 static int db_return_states_assign(struct expression
*expr
)
475 struct expression
*right
;
477 struct state_list
*slist
;
480 right
= strip_expr(expr
->right
);
481 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
486 db_info
.slist
= NULL
;
488 call_return_states_before_hooks();
490 __push_fake_cur_slist();
491 sql_select_return_states("return_id, return, type, parameter, key, value",
492 right
, db_assign_return_states_callback
);
493 slist
= __pop_fake_cur_slist();
494 merge_slist(&db_info
.slist
, slist
);
496 FOR_EACH_PTR(db_info
.slist
, sm
) {
499 } END_FOR_EACH_PTR(sm
);
501 call_return_states_after_hooks();
506 static int handle_implied_return(struct expression
*expr
)
508 struct range_list
*rl
;
510 if (!get_implied_return(expr
->right
, &rl
))
512 rl
= cast_rl(get_type(expr
->left
), rl
);
513 set_extra_expr_mod(expr
->left
, alloc_estate_rl(rl
));
517 static void match_assign_call(struct expression
*expr
)
519 struct call_back_list
*call_backs
;
521 struct expression
*right
;
524 right
= strip_expr(expr
->right
);
525 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
) {
526 set_extra_expr_mod(expr
->left
, alloc_estate_whole(get_type(expr
->left
)));
529 fn
= right
->fn
->symbol
->ident
->name
;
532 * some of these conflict (they try to set smatch extra twice), so we
533 * call them in order from least important to most important.
536 call_backs
= search_callback(func_hash
, (char *)fn
);
537 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
539 handled
|= db_return_states_assign(expr
);
540 handled
|= assign_ranged_funcs(fn
, expr
, call_backs
);
541 handled
|= handle_implied_return(expr
);
544 struct range_list
*rl
;
546 if (!get_implied_rl(expr
->right
, &rl
))
547 rl
= alloc_whole_rl(get_type(expr
->right
));
548 rl
= cast_rl(get_type(expr
->left
), rl
);
549 set_extra_expr_mod(expr
->left
, alloc_estate_rl(rl
));
553 static int db_return_states_callback(void *unused
, int argc
, char **argv
, char **azColName
)
555 struct range_list
*ret_range
;
558 struct return_implies_callback
*tmp
;
559 struct state_list
*slist
;
565 return_id
= atoi(argv
[0]);
566 str_to_rl(get_type(strip_expr(db_info
.expr
)), argv
[1], &ret_range
);
567 ret_range
= cast_rl(get_type(db_info
.expr
), ret_range
);
568 type
= atoi(argv
[2]);
569 param
= atoi(argv
[3]);
573 if (prev_return_id
!= -1 && return_id
!= prev_return_id
) {
574 slist
= __pop_fake_cur_slist();
575 merge_slist(&db_info
.slist
, slist
);
576 __push_fake_cur_slist();
579 prev_return_id
= return_id
;
581 FOR_EACH_PTR(db_return_states_list
, tmp
) {
582 if (tmp
->type
== type
)
583 tmp
->callback(db_info
.expr
, param
, key
, value
);
584 } END_FOR_EACH_PTR(tmp
);
589 static void db_return_states(struct expression
*expr
)
592 struct state_list
*slist
;
594 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
596 if (!__get_cur_slist()) /* no return functions */
601 db_info
.slist
= NULL
;
603 call_return_states_before_hooks();
605 __push_fake_cur_slist();
607 sql_select_return_states("return_id, return, type, parameter, key, value",
608 expr
, db_return_states_callback
);
609 slist
= __pop_fake_cur_slist();
610 merge_slist(&db_info
.slist
, slist
);
612 FOR_EACH_PTR(db_info
.slist
, sm
) {
614 } END_FOR_EACH_PTR(sm
);
616 call_return_states_after_hooks();
619 static int is_assigned_call(struct expression
*expr
)
621 struct expression
*tmp
;
623 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
624 if (tmp
->type
== EXPR_ASSIGNMENT
&& strip_expr(tmp
->right
) == expr
)
626 if (tmp
->pos
.line
< expr
->pos
.line
)
628 } END_FOR_EACH_PTR_REVERSE(tmp
);
632 static void db_return_states_call(struct expression
*expr
)
634 if (is_assigned_call(expr
))
636 db_return_states(expr
);
639 static void match_function_call(struct expression
*expr
)
641 struct call_back_list
*call_backs
;
643 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
645 call_backs
= search_callback(func_hash
, (char *)expr
->fn
->symbol
->ident
->name
);
647 call_call_backs(call_backs
, REGULAR_CALL
,
648 expr
->fn
->symbol
->ident
->name
, expr
);
649 db_return_states_call(expr
);
652 static void match_macro_assign(struct expression
*expr
)
654 struct call_back_list
*call_backs
;
656 struct expression
*right
;
658 right
= strip_expr(expr
->right
);
659 macro
= get_macro_name(right
->pos
);
660 call_backs
= search_callback(func_hash
, (char *)macro
);
663 call_call_backs(call_backs
, MACRO_ASSIGN
, macro
, expr
);
664 call_call_backs(call_backs
, MACRO_ASSIGN_EXTRA
, macro
, expr
);
667 int get_implied_return(struct expression
*expr
, struct range_list
**rl
)
669 struct call_back_list
*call_backs
;
670 struct fcall_back
*tmp
;
676 expr
= strip_expr(expr
);
677 fn
= expr_to_var(expr
->fn
);
681 call_backs
= search_callback(func_hash
, fn
);
683 FOR_EACH_PTR(call_backs
, tmp
) {
684 if (tmp
->type
== IMPLIED_RETURN
) {
685 (tmp
->u
.implied_return
)(expr
, tmp
->info
, rl
);
688 } END_FOR_EACH_PTR(tmp
);
695 void create_function_hook_hash(void)
697 func_hash
= create_function_hashtable(5000);
700 void register_function_hooks(int id
)
702 add_hook(&match_function_call
, CALL_HOOK_AFTER_INLINE
);
703 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
704 add_hook(&match_macro_assign
, MACRO_ASSIGNMENT_HOOK
);