db: make some varchar decalarations smaller
[smatch.git] / smatch_function_hooks.c
blob3faadef6f6bd445a849a86b43296da991fa46a4c
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 static struct fcall_back *alloc_fcall_back(int type, void *call_back,
61 void *info)
63 struct fcall_back *cb;
65 cb = __alloc_fcall_back(0);
66 cb->type = type;
67 cb->u.call_back = call_back;
68 cb->info = info;
69 return cb;
72 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
74 struct fcall_back *cb;
76 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
77 add_callback(func_hash, look_for, cb);
80 void add_function_assign_hook(const char *look_for, func_hook *call_back,
81 void *info)
83 struct fcall_back *cb;
85 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
86 add_callback(func_hash, look_for, cb);
89 void add_implied_return_hook(const char *look_for,
90 implied_return_hook *call_back,
91 void *info)
93 struct fcall_back *cb;
95 cb = alloc_fcall_back(IMPLIED_RETURN, call_back, info);
96 add_callback(func_hash, look_for, cb);
99 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
100 void *info)
102 struct fcall_back *cb;
104 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
105 add_callback(func_hash, look_for, cb);
108 void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
109 void *info)
111 struct fcall_back *cb;
113 cb = alloc_fcall_back(MACRO_ASSIGN_EXTRA, call_back, info);
114 add_callback(func_hash, look_for, cb);
117 void return_implies_state(const char *look_for, long long start, long long end,
118 implication_hook *call_back, void *info)
120 struct fcall_back *cb;
122 cb = alloc_fcall_back(RANGED_CALL, call_back, info);
123 cb->range = alloc_range_perm(ll_to_sval(start), ll_to_sval(end));
124 add_callback(func_hash, look_for, cb);
127 void add_db_return_states_callback(int type, return_implies_hook *callback)
129 struct return_implies_callback *cb = __alloc_return_implies_callback(0);
131 cb->type = type;
132 cb->callback = callback;
133 add_ptr_list(&db_return_states_list, cb);
136 static int call_call_backs(struct call_back_list *list, int type,
137 const char *fn, struct expression *expr)
139 struct fcall_back *tmp;
140 int handled = 0;
142 FOR_EACH_PTR(list, tmp) {
143 if (tmp->type == type) {
144 (tmp->u.call_back)(fn, expr, tmp->info);
145 handled = 1;
147 } END_FOR_EACH_PTR(tmp);
149 return handled;
152 static void call_ranged_call_backs(struct call_back_list *list,
153 const char *fn, struct expression *call_expr,
154 struct expression *assign_expr)
156 struct fcall_back *tmp;
158 FOR_EACH_PTR(list, tmp) {
159 (tmp->u.ranged)(fn, call_expr, assign_expr, tmp->info);
160 } END_FOR_EACH_PTR(tmp);
163 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
164 struct data_range *drange)
166 struct call_back_list *ret = NULL;
167 struct fcall_back *tmp;
169 FOR_EACH_PTR(list, tmp) {
170 if (tmp->type != RANGED_CALL)
171 continue;
172 if (ranges_equiv(tmp->range, drange))
173 add_ptr_list(&ret, tmp);
174 } END_FOR_EACH_PTR(tmp);
175 return ret;
178 static int in_list_exact_sval(struct range_list *list, struct data_range *drange)
180 struct data_range *tmp;
182 FOR_EACH_PTR(list, tmp) {
183 if (ranges_equiv(tmp, drange))
184 return 1;
185 } END_FOR_EACH_PTR(tmp);
186 return 0;
189 static int assign_ranged_funcs(const char *fn, struct expression *expr,
190 struct call_back_list *call_backs)
192 struct fcall_back *tmp;
193 struct sm_state *sm;
194 char *var_name;
195 struct symbol *sym;
196 struct smatch_state *estate;
197 struct state_list *tmp_slist;
198 struct state_list *final_states = NULL;
199 struct range_list *handled_ranges = NULL;
200 struct call_back_list *same_range_call_backs = NULL;
201 int handled = 0;
203 if (!call_backs)
204 return 0;
206 var_name = get_variable_from_expr(expr->left, &sym);
207 if (!var_name || !sym)
208 goto free;
210 FOR_EACH_PTR(call_backs, tmp) {
211 if (tmp->type != RANGED_CALL)
212 continue;
214 if (in_list_exact_sval(handled_ranges, tmp->range))
215 continue;
216 __push_fake_cur_slist();
217 tack_on(&handled_ranges, tmp->range);
219 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
220 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
221 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
223 estate = alloc_estate_range(tmp->range->min, tmp->range->max);
224 set_extra_mod(var_name, sym, estate);
226 tmp_slist = __pop_fake_cur_slist();
227 merge_slist(&final_states, tmp_slist);
228 free_slist(&tmp_slist);
229 handled = 1;
230 } END_FOR_EACH_PTR(tmp);
232 FOR_EACH_PTR(final_states, sm) {
233 __set_sm(sm);
234 } END_FOR_EACH_PTR(sm);
236 free_slist(&final_states);
237 free:
238 free_string(var_name);
239 return handled;
242 static int call_implies_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
244 struct call_back_list *call_backs;
245 struct fcall_back *tmp;
246 const char *fn;
247 struct data_range *value_range;
248 struct state_list *true_states = NULL;
249 struct state_list *false_states = NULL;
250 struct state_list *tmp_slist;
251 struct sm_state *sm;
253 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
254 return 0;
255 fn = expr->fn->symbol->ident->name;
256 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
257 if (!call_backs)
258 return 0;
259 value_range = alloc_range(sval, sval);
261 /* set true states */
262 __push_fake_cur_slist();
263 FOR_EACH_PTR(call_backs, tmp) {
264 if (tmp->type != RANGED_CALL)
265 continue;
266 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
267 continue;
268 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
269 } END_FOR_EACH_PTR(tmp);
270 tmp_slist = __pop_fake_cur_slist();
271 merge_slist(&true_states, tmp_slist);
272 free_slist(&tmp_slist);
274 /* set false states */
275 __push_fake_cur_slist();
276 FOR_EACH_PTR(call_backs, tmp) {
277 if (tmp->type != RANGED_CALL)
278 continue;
279 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
280 continue;
281 (tmp->u.ranged)(fn, expr, NULL, tmp->info);
282 } END_FOR_EACH_PTR(tmp);
283 tmp_slist = __pop_fake_cur_slist();
284 merge_slist(&false_states, tmp_slist);
285 free_slist(&tmp_slist);
287 FOR_EACH_PTR(true_states, sm) {
288 __set_true_false_sm(sm, NULL);
289 } END_FOR_EACH_PTR(sm);
290 FOR_EACH_PTR(false_states, sm) {
291 __set_true_false_sm(NULL, sm);
292 } END_FOR_EACH_PTR(sm);
294 free_slist(&true_states);
295 free_slist(&false_states);
296 return 1;
299 struct db_callback_info {
300 int true_side;
301 int comparison;
302 struct expression *expr;
303 struct range_list *rl;
304 int left;
305 struct state_list *slist;
306 struct db_implies_list *callbacks;
308 static struct db_callback_info db_info;
309 static int db_compare_callback(void *unused, int argc, char **argv, char **azColName)
311 struct range_list *ret_range;
312 int type, param;
313 char *key, *value;
314 struct return_implies_callback *tmp;
316 if (argc != 5)
317 return 0;
319 parse_value_ranges_type(get_type(db_info.expr), argv[0], &ret_range);
320 type = atoi(argv[1]);
321 param = atoi(argv[2]);
322 key = argv[3];
323 value = argv[4];
325 if (db_info.true_side) {
326 if (!possibly_true_range_lists_lr(db_info.comparison,
327 ret_range, db_info.rl,
328 db_info.left))
329 return 0;
330 } else {
331 if (!possibly_false_range_lists_lr(db_info.comparison,
332 ret_range, db_info.rl,
333 db_info.left))
334 return 0;
337 FOR_EACH_PTR(db_info.callbacks, tmp) {
338 if (tmp->type == type)
339 tmp->callback(db_info.expr, param, key, value);
340 } END_FOR_EACH_PTR(tmp);
341 return 0;
344 void compare_db_return_states_callbacks(int comparison, struct expression *expr, sval_t sval, int left)
346 struct symbol *sym;
347 static char sql_filter[1024];
348 struct state_list *true_states;
349 struct state_list *false_states;
350 struct sm_state *sm;
352 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
353 return;
355 sym = expr->fn->symbol;
356 if (!sym)
357 return;
359 if (sym->ctype.modifiers & MOD_STATIC) {
360 snprintf(sql_filter, 1024,
361 "file = '%s' and function = '%s' and static = '1';",
362 get_filename(), sym->ident->name);
363 } else {
364 snprintf(sql_filter, 1024,
365 "function = '%s' and static = '0';", sym->ident->name);
368 db_info.comparison = comparison;
369 db_info.expr = expr;
370 db_info.rl = alloc_range_list(sval, sval);
371 db_info.left = left;
372 db_info.callbacks = db_return_states_list;
374 db_info.true_side = 1;
375 __push_fake_cur_slist();
376 run_sql(db_compare_callback,
377 "select return, type, parameter, key, value from return_states where %s",
378 sql_filter);
379 true_states = __pop_fake_cur_slist();
381 db_info.true_side = 0;
382 __push_fake_cur_slist();
383 run_sql(db_compare_callback,
384 "select return, type, parameter, key, value from return_states where %s",
385 sql_filter);
386 false_states = __pop_fake_cur_slist();
388 FOR_EACH_PTR(true_states, sm) {
389 __set_true_false_sm(sm, NULL);
390 } END_FOR_EACH_PTR(sm);
391 FOR_EACH_PTR(false_states, sm) {
392 __set_true_false_sm(NULL, sm);
393 } END_FOR_EACH_PTR(sm);
395 free_slist(&true_states);
396 free_slist(&false_states);
401 void function_comparison(int comparison, struct expression *expr, sval_t sval, int left)
403 if (call_implies_callbacks(comparison, expr, sval, left))
404 return;
405 compare_db_return_states_callbacks(comparison, expr, sval, left);
408 static int prev_return_id;
409 static int db_assign_return_states_callback(void *unused, int argc, char **argv, char **azColName)
411 struct range_list *ret_range;
412 int type, param;
413 char *key, *value;
414 struct return_implies_callback *tmp;
415 struct state_list *slist;
416 int return_id;
418 if (argc != 6)
419 return 0;
421 return_id = atoi(argv[0]);
422 parse_value_ranges_type(get_type(db_info.expr->right), argv[1], &ret_range);
423 if (!ret_range)
424 ret_range = whole_range_list(cur_func_return_type());
425 type = atoi(argv[2]);
426 param = atoi(argv[3]);
427 key = argv[4];
428 value = argv[5];
430 if (prev_return_id != -1 && return_id != prev_return_id) {
431 slist = __pop_fake_cur_slist();
432 merge_slist(&db_info.slist, slist);
433 __push_fake_cur_slist();
435 prev_return_id = return_id;
437 FOR_EACH_PTR(db_return_states_list, tmp) {
438 if (tmp->type == type)
439 tmp->callback(db_info.expr, param, key, value);
440 } END_FOR_EACH_PTR(tmp);
441 ret_range = cast_rl(get_type(db_info.expr->left), ret_range);
442 set_extra_expr_mod(db_info.expr->left, alloc_estate_range_list(ret_range));
444 return 0;
447 static int db_return_states_assign(struct expression *expr)
449 struct expression *right;
450 struct symbol *sym;
451 struct sm_state *sm;
452 struct state_list *slist;
453 static char sql_filter[1024];
454 int handled = 0;
456 right = strip_expr(expr->right);
457 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
458 return 0;
460 sym = right->fn->symbol;
461 if (!sym)
462 return 0;
464 if (sym->ctype.modifiers & MOD_STATIC) {
465 snprintf(sql_filter, 1024,
466 "file = '%s' and function = '%s' and static = '1';",
467 get_filename(), sym->ident->name);
468 } else {
469 snprintf(sql_filter, 1024,
470 "function = '%s' and static = '0';", sym->ident->name);
473 prev_return_id = -1;
474 db_info.expr = expr;
475 db_info.slist = NULL;
476 __push_fake_cur_slist();
477 run_sql(db_assign_return_states_callback,
478 "select return_id, return, type, parameter, key, value from return_states where %s",
479 sql_filter);
480 slist = __pop_fake_cur_slist();
481 merge_slist(&db_info.slist, slist);
483 FOR_EACH_PTR(db_info.slist, sm) {
484 __set_sm(sm);
485 handled = 1;
486 } END_FOR_EACH_PTR(sm);
488 return handled;
491 static int handle_implied_return(struct expression *expr)
493 struct range_list *rl;
495 if (!get_implied_return(expr->right, &rl))
496 return 0;
497 rl = cast_rl(get_type(expr->left), rl);
498 set_extra_expr_mod(expr->left, alloc_estate_range_list(rl));
499 return 1;
502 static void match_assign_call(struct expression *expr)
504 struct call_back_list *call_backs;
505 const char *fn;
506 struct expression *right;
507 int handled = 0;
509 right = strip_expr(expr->right);
510 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol) {
511 set_extra_expr_mod(expr->left, extra_undefined(get_type(expr->left)));
512 return;
514 fn = right->fn->symbol->ident->name;
517 * some of these conflict (they try to set smatch extra twice), so we
518 * call them in order from least important to most important.
521 call_backs = search_callback(func_hash, (char *)fn);
522 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
524 handled |= db_return_states_assign(expr);
525 handled |= assign_ranged_funcs(fn, expr, call_backs);
526 handled |= handle_implied_return(expr);
528 if (!handled) {
529 struct range_list *rl;
531 if (!get_implied_range_list(expr->right, &rl))
532 rl = whole_range_list(get_type(expr->right));
533 rl = cast_rl(get_type(expr->left), rl);
534 set_extra_expr_mod(expr->left, alloc_estate_range_list(rl));
538 static int db_return_states_callback(void *unused, int argc, char **argv, char **azColName)
540 struct range_list *ret_range;
541 int type, param;
542 char *key, *value;
543 struct return_implies_callback *tmp;
544 struct state_list *slist;
545 int return_id;
547 if (argc != 6)
548 return 0;
550 return_id = atoi(argv[0]);
551 parse_value_ranges_type(get_type(db_info.expr), argv[1], &ret_range);
552 type = atoi(argv[2]);
553 param = atoi(argv[3]);
554 key = argv[4];
555 value = argv[5];
557 if (prev_return_id != -1 && return_id != prev_return_id) {
558 slist = __pop_fake_cur_slist();
559 merge_slist(&db_info.slist, slist);
560 __push_fake_cur_slist();
561 __unnullify_path();
563 prev_return_id = return_id;
565 FOR_EACH_PTR(db_return_states_list, tmp) {
566 if (tmp->type == type)
567 tmp->callback(db_info.expr, param, key, value);
568 } END_FOR_EACH_PTR(tmp);
570 return 0;
573 static void db_return_states(struct expression *expr)
575 struct symbol *sym;
576 struct sm_state *sm;
577 struct state_list *slist;
578 static char sql_filter[1024];
580 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
581 return;
583 sym = expr->fn->symbol;
584 if (!sym)
585 return;
587 if (sym->ctype.modifiers & MOD_STATIC) {
588 snprintf(sql_filter, 1024,
589 "file = '%s' and function = '%s' and static = '1';",
590 get_filename(), sym->ident->name);
591 } else {
592 snprintf(sql_filter, 1024,
593 "function = '%s' and static = '0';", sym->ident->name);
596 prev_return_id = -1;
597 db_info.expr = expr;
598 db_info.slist = NULL;
599 __push_fake_cur_slist();
600 __unnullify_path();
601 run_sql(db_return_states_callback,
602 "select return_id, return, type, parameter, key, value from return_states where %s",
603 sql_filter);
604 slist = __pop_fake_cur_slist();
605 merge_slist(&db_info.slist, slist);
607 FOR_EACH_PTR(db_info.slist, sm) {
608 __set_sm(sm);
609 } END_FOR_EACH_PTR(sm);
612 static int is_assigned_call(struct expression *expr)
614 struct expression *tmp;
616 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
617 if (tmp->type == EXPR_ASSIGNMENT && strip_expr(tmp->right) == expr)
618 return 1;
619 if (tmp->pos.line < expr->pos.line)
620 return 0;
621 } END_FOR_EACH_PTR_REVERSE(tmp);
622 return 0;
625 static void db_return_states_call(struct expression *expr)
627 if (is_assigned_call(expr))
628 return;
629 db_return_states(expr);
632 static void match_function_call(struct expression *expr)
634 struct call_back_list *call_backs;
636 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
637 return;
638 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
639 if (call_backs)
640 call_call_backs(call_backs, REGULAR_CALL,
641 expr->fn->symbol->ident->name, expr);
642 db_return_states_call(expr);
645 static void match_macro_assign(struct expression *expr)
647 struct call_back_list *call_backs;
648 const char *macro;
649 struct expression *right;
651 right = strip_expr(expr->right);
652 macro = get_macro_name(right->pos);
653 call_backs = search_callback(func_hash, (char *)macro);
654 if (!call_backs)
655 return;
656 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
657 call_call_backs(call_backs, MACRO_ASSIGN_EXTRA, macro, expr);
660 int get_implied_return(struct expression *expr, struct range_list **rl)
662 struct call_back_list *call_backs;
663 struct fcall_back *tmp;
664 int handled = 0;
665 char *fn;
667 *rl = NULL;
669 expr = strip_expr(expr);
670 fn = get_variable_from_expr(expr->fn, NULL);
671 if (!fn)
672 goto out;
674 call_backs = search_callback(func_hash, fn);
676 FOR_EACH_PTR(call_backs, tmp) {
677 if (tmp->type == IMPLIED_RETURN) {
678 (tmp->u.implied_return)(expr, tmp->info, rl);
679 handled = 1;
681 } END_FOR_EACH_PTR(tmp);
683 out:
684 free_string(fn);
685 return handled;
688 void create_function_hook_hash(void)
690 func_hash = create_function_hashtable(5000);
693 void register_function_hooks(int id)
695 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
696 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
697 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);