db: fix call_implies for the in-memory database
[smatch.git] / smatch_function_hooks.c
blobe9409d2858222a0f6f736ffe1709a4371f313327
1 /*
2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
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.
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "smatch.h"
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
26 #include "smatch_function_hashtable.h"
28 struct fcall_back {
29 int type;
30 struct data_range *range;
31 union {
32 func_hook *call_back;
33 implication_hook *ranged;
34 implied_return_hook *implied_return;
35 } u;
36 void *info;
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
46 #define RANGED_CALL 1
47 #define ASSIGN_CALL 2
48 #define IMPLIED_RETURN 3
49 #define MACRO_ASSIGN 4
50 #define MACRO_ASSIGN_EXTRA 5
52 struct return_implies_callback {
53 int type;
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,
66 void *info)
68 struct fcall_back *cb;
70 cb = __alloc_fcall_back(0);
71 cb->type = type;
72 cb->u.call_back = call_back;
73 cb->info = info;
74 return cb;
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,
86 void *info)
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,
96 void *info)
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,
105 void *info)
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,
114 void *info)
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);
136 cb->type = type;
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 *));
144 *p = 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 *));
151 *p = fn;
152 add_ptr_list(&return_states_after, p);
155 static void call_return_states_before_hooks(void)
157 void_fn **fn;
159 FOR_EACH_PTR(return_states_before, fn) {
160 (*fn)();
161 } END_FOR_EACH_PTR(fn);
164 static void call_return_states_after_hooks(void)
166 void_fn **fn;
168 FOR_EACH_PTR(return_states_after, fn) {
169 (*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;
177 int handled = 0;
179 FOR_EACH_PTR(list, tmp) {
180 if (tmp->type == type) {
181 (tmp->u.call_back)(fn, expr, tmp->info);
182 handled = 1;
184 } END_FOR_EACH_PTR(tmp);
186 return handled;
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)
208 continue;
209 if (ranges_equiv(tmp->range, drange))
210 add_ptr_list(&ret, tmp);
211 } END_FOR_EACH_PTR(tmp);
212 return ret;
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))
221 return 1;
222 } END_FOR_EACH_PTR(tmp);
223 return 0;
226 static int assign_ranged_funcs(const char *fn, struct expression *expr,
227 struct call_back_list *call_backs)
229 struct fcall_back *tmp;
230 struct sm_state *sm;
231 char *var_name;
232 struct symbol *sym;
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;
238 int handled = 0;
240 if (!call_backs)
241 return 0;
243 var_name = expr_to_var_sym(expr->left, &sym);
244 if (!var_name || !sym)
245 goto free;
247 FOR_EACH_PTR(call_backs, tmp) {
248 if (tmp->type != RANGED_CALL)
249 continue;
251 if (in_list_exact_sval(handled_ranges, tmp->range))
252 continue;
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);
266 handled = 1;
267 } END_FOR_EACH_PTR(tmp);
269 FOR_EACH_PTR(final_states, sm) {
270 __set_sm(sm);
271 } END_FOR_EACH_PTR(sm);
273 free_slist(&final_states);
274 free:
275 free_string(var_name);
276 return handled;
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;
283 const char *fn;
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;
288 struct sm_state *sm;
290 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
291 return 0;
292 fn = expr->fn->symbol->ident->name;
293 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
294 if (!call_backs)
295 return 0;
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)
302 continue;
303 if (!true_comparison_range_LR(comparison, tmp->range, value_range, left))
304 continue;
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)
315 continue;
316 if (!false_comparison_range_LR(comparison, tmp->range, value_range, left))
317 continue;
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);
333 return 1;
336 struct db_callback_info {
337 int true_side;
338 int comparison;
339 struct expression *expr;
340 struct range_list *rl;
341 int left;
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;
349 int type, param;
350 char *key, *value;
351 struct return_implies_callback *tmp;
353 if (argc != 5)
354 return 0;
356 str_to_rl(get_type(db_info.expr), argv[0], &ret_range);
357 type = atoi(argv[1]);
358 param = atoi(argv[2]);
359 key = argv[3];
360 value = argv[4];
362 if (db_info.true_side) {
363 if (!possibly_true_rl_LR(db_info.comparison,
364 ret_range, db_info.rl,
365 db_info.left))
366 return 0;
367 } else {
368 if (!possibly_false_rl_LR(db_info.comparison,
369 ret_range, db_info.rl,
370 db_info.left))
371 return 0;
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);
378 return 0;
381 void compare_db_return_states_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
383 struct state_list *true_states;
384 struct state_list *false_states;
385 struct sm_state *sm;
387 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
388 return;
390 db_info.comparison = comparison;
391 db_info.expr = expr;
392 db_info.rl = alloc_rl(sval, sval);
393 db_info.left = left;
394 db_info.callbacks = db_return_states_list;
396 call_return_states_before_hooks();
398 db_info.true_side = 1;
399 __push_fake_cur_slist();
400 sql_select_return_states("return, type, parameter, key, value", expr,
401 db_compare_callback);
402 true_states = __pop_fake_cur_slist();
404 db_info.true_side = 0;
405 __push_fake_cur_slist();
406 sql_select_return_states("return, type, parameter, key, value", expr,
407 db_compare_callback);
408 false_states = __pop_fake_cur_slist();
410 FOR_EACH_PTR(true_states, sm) {
411 __set_true_false_sm(sm, NULL);
412 } END_FOR_EACH_PTR(sm);
413 FOR_EACH_PTR(false_states, sm) {
414 __set_true_false_sm(NULL, sm);
415 } END_FOR_EACH_PTR(sm);
417 call_return_states_after_hooks();
419 free_slist(&true_states);
420 free_slist(&false_states);
425 void function_comparison(int comparison, struct expression *expr, sval_t sval, int left)
427 if (call_implies_callbacks(comparison, expr, sval, left))
428 return;
429 compare_db_return_states_callbacks(comparison, expr, sval, left);
432 static int prev_return_id;
433 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
435 struct range_list *ret_range;
436 int type, param;
437 char *key, *value;
438 struct return_implies_callback *tmp;
439 struct state_list *slist;
440 int return_id;
442 if (argc != 6)
443 return 0;
445 return_id = atoi(argv[0]);
446 str_to_rl(get_type(db_info.expr->right), argv[1], &ret_range);
447 if (!ret_range)
448 ret_range = alloc_whole_rl(cur_func_return_type());
449 type = atoi(argv[2]);
450 param = atoi(argv[3]);
451 key = argv[4];
452 value = argv[5];
454 if (prev_return_id != -1 && return_id != prev_return_id) {
455 slist = __pop_fake_cur_slist();
456 merge_slist(&db_info.slist, slist);
457 __push_fake_cur_slist();
459 prev_return_id = return_id;
461 FOR_EACH_PTR(db_return_states_list, tmp) {
462 if (tmp->type == type)
463 tmp->callback(db_info.expr, param, key, value);
464 } END_FOR_EACH_PTR(tmp);
465 ret_range = cast_rl(get_type(db_info.expr->left), ret_range);
466 set_extra_expr_mod(db_info.expr->left, alloc_estate_rl(ret_range));
468 return 0;
471 static int db_return_states_assign(struct expression *expr)
473 struct expression *right;
474 struct sm_state *sm;
475 struct state_list *slist;
476 int handled = 0;
478 right = strip_expr(expr->right);
479 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
480 return 0;
482 prev_return_id = -1;
483 db_info.expr = expr;
484 db_info.slist = NULL;
486 call_return_states_before_hooks();
488 __push_fake_cur_slist();
489 sql_select_return_states("return_id, return, type, parameter, key, value",
490 right, db_assign_return_states_callback);
491 slist = __pop_fake_cur_slist();
492 merge_slist(&db_info.slist, slist);
494 FOR_EACH_PTR(db_info.slist, sm) {
495 __set_sm(sm);
496 handled = 1;
497 } END_FOR_EACH_PTR(sm);
499 call_return_states_after_hooks();
501 return handled;
504 static int handle_implied_return(struct expression *expr)
506 struct range_list *rl;
508 if (!get_implied_return(expr->right, &rl))
509 return 0;
510 rl = cast_rl(get_type(expr->left), rl);
511 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
512 return 1;
515 static void match_assign_call(struct expression *expr)
517 struct call_back_list *call_backs;
518 const char *fn;
519 struct expression *right;
520 int handled = 0;
522 right = strip_expr(expr->right);
523 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
524 set_extra_expr_mod(expr->left, alloc_estate_whole(get_type(expr->left)));
525 return;
527 fn = right->fn->symbol->ident->name;
530 * some of these conflict (they try to set smatch extra twice), so we
531 * call them in order from least important to most important.
534 call_backs = search_callback(func_hash, (char *)fn);
535 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
537 handled |= db_return_states_assign(expr);
538 handled |= assign_ranged_funcs(fn, expr, call_backs);
539 handled |= handle_implied_return(expr);
541 if (!handled) {
542 struct range_list *rl;
544 if (!get_implied_rl(expr->right, &rl))
545 rl = alloc_whole_rl(get_type(expr->right));
546 rl = cast_rl(get_type(expr->left), rl);
547 set_extra_expr_mod(expr->left, alloc_estate_rl(rl));
551 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
553 struct range_list *ret_range;
554 int type, param;
555 char *key, *value;
556 struct return_implies_callback *tmp;
557 struct state_list *slist;
558 int return_id;
560 if (argc != 6)
561 return 0;
563 return_id = atoi(argv[0]);
564 str_to_rl(get_type(db_info.expr), argv[1], &ret_range);
565 type = atoi(argv[2]);
566 param = atoi(argv[3]);
567 key = argv[4];
568 value = argv[5];
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();
574 __unnullify_path();
576 prev_return_id = return_id;
578 FOR_EACH_PTR(db_return_states_list, tmp) {
579 if (tmp->type == type)
580 tmp->callback(db_info.expr, param, key, value);
581 } END_FOR_EACH_PTR(tmp);
583 return 0;
586 static void db_return_states(struct expression *expr)
588 struct sm_state *sm;
589 struct state_list *slist;
591 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
592 return;
593 if (!__get_cur_slist()) /* no return functions */
594 return;
596 prev_return_id = -1;
597 db_info.expr = expr;
598 db_info.slist = NULL;
600 call_return_states_before_hooks();
602 __push_fake_cur_slist();
603 __unnullify_path();
604 sql_select_return_states("return_id, return, type, parameter, key, value",
605 expr, db_return_states_callback);
606 slist = __pop_fake_cur_slist();
607 merge_slist(&db_info.slist, slist);
609 FOR_EACH_PTR(db_info.slist, sm) {
610 __set_sm(sm);
611 } END_FOR_EACH_PTR(sm);
613 call_return_states_after_hooks();
616 static int is_assigned_call(struct expression *expr)
618 struct expression *tmp;
620 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
621 if (tmp->type == EXPR_ASSIGNMENT && strip_expr(tmp->right) == expr)
622 return 1;
623 if (tmp->pos.line < expr->pos.line)
624 return 0;
625 } END_FOR_EACH_PTR_REVERSE(tmp);
626 return 0;
629 static void db_return_states_call(struct expression *expr)
631 if (is_assigned_call(expr))
632 return;
633 db_return_states(expr);
636 static void match_function_call(struct expression *expr)
638 struct call_back_list *call_backs;
640 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
641 return;
642 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
643 if (call_backs)
644 call_call_backs(call_backs, REGULAR_CALL,
645 expr->fn->symbol->ident->name, expr);
646 db_return_states_call(expr);
649 static void match_macro_assign(struct expression *expr)
651 struct call_back_list *call_backs;
652 const char *macro;
653 struct expression *right;
655 right = strip_expr(expr->right);
656 macro = get_macro_name(right->pos);
657 call_backs = search_callback(func_hash, (char *)macro);
658 if (!call_backs)
659 return;
660 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
661 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
664 int get_implied_return(struct expression *expr, struct range_list **rl)
666 struct call_back_list *call_backs;
667 struct fcall_back *tmp;
668 int handled = 0;
669 char *fn;
671 *rl = NULL;
673 expr = strip_expr(expr);
674 fn = expr_to_var(expr->fn);
675 if (!fn)
676 goto out;
678 call_backs = search_callback(func_hash, fn);
680 FOR_EACH_PTR(call_backs, tmp) {
681 if (tmp->type == IMPLIED_RETURN) {
682 (tmp->u.implied_return)(expr, tmp->info, rl);
683 handled = 1;
685 } END_FOR_EACH_PTR(tmp);
687 out:
688 free_string(fn);
689 return handled;
692 void create_function_hook_hash(void)
694 func_hash = create_function_hashtable(5000);
697 void register_function_hooks(int id)
699 add_hook(&match_function_call, CALL_HOOK_AFTER_INLINE);
700 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
701 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);