introduce: get_dinfo()
[smatch.git] / smatch_extra.c
blob3d775249abe5c8a8f8ce67afff6a01fe24b22048
1 /*
2 * sparse/smatch_extra.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * smatch_extra.c is supposed to track the value of every variable.
14 #include <stdlib.h>
15 #define __USE_ISOC99
16 #include <limits.h>
17 #include "parse.h"
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static int my_id;
24 static struct symbol *cur_func;
26 struct data_range whole_range = {
27 .min = LLONG_MIN,
28 .max = LLONG_MAX,
31 static struct smatch_state *alloc_extra_state_empty()
33 struct smatch_state *state;
34 struct data_info *dinfo;
36 dinfo = __alloc_data_info(0);
37 dinfo->type = DATA_RANGE;
38 dinfo->value_ranges = NULL;
39 state = __alloc_smatch_state(0);
40 state->data = dinfo;
41 return state;
44 static struct smatch_state *alloc_extra_state_no_name(int val)
46 struct smatch_state *state;
48 state = __alloc_smatch_state(0);
49 state->data = (void *)alloc_dinfo_range(val, val);
50 return state;
53 /* We do this because ->value_ranges is a list */
54 struct smatch_state *extra_undefined()
56 struct data_info *dinfo;
57 static struct smatch_state *ret;
58 static struct symbol *prev_func;
60 if (prev_func == cur_func)
61 return ret;
62 prev_func = cur_func;
64 dinfo = alloc_dinfo_range(whole_range.min, whole_range.max);
65 ret = __alloc_smatch_state(0);
66 ret->name = "unknown";
67 ret->data = dinfo;
68 return ret;
71 struct smatch_state *alloc_extra_state(int val)
73 struct smatch_state *state;
75 state = alloc_extra_state_no_name(val);
76 state->name = show_ranges(((struct data_info *)state->data)->value_ranges);
77 return state;
80 struct smatch_state *alloc_extra_state_range(long long min, long long max)
82 struct smatch_state *state;
84 if (min == whole_range.min && max == whole_range.max)
85 return extra_undefined();
86 state = __alloc_smatch_state(0);
87 state->data = (void *)alloc_dinfo_range(min, max);
88 state->name = show_ranges(((struct data_info *)state->data)->value_ranges);
89 return state;
92 struct smatch_state *alloc_extra_state_range_list(struct range_list *rl)
94 struct smatch_state *state;
96 state = __alloc_smatch_state(0);
97 state->data = (void *)alloc_dinfo_range_list(rl);
98 state->name = show_ranges(((struct data_info *)state->data)->value_ranges);
99 return state;
102 struct data_info *get_dinfo(struct smatch_state *state)
104 if (!state)
105 return NULL;
106 return (struct data_info *)state->data;
110 struct smatch_state *filter_range(struct smatch_state *orig,
111 long long filter_min, long long filter_max)
113 struct smatch_state *ret;
114 struct data_info *orig_info;
115 struct data_info *ret_info;
117 if (!orig)
118 orig = extra_undefined();
119 orig_info = (struct data_info *)orig->data;
120 ret = alloc_extra_state_empty();
121 ret_info = (struct data_info *)ret->data;
122 ret_info->value_ranges = remove_range(orig_info->value_ranges, filter_min, filter_max);
123 ret->name = show_ranges(ret_info->value_ranges);
124 return ret;
127 struct smatch_state *add_filter(struct smatch_state *orig, long long num)
129 return filter_range(orig, num, num);
132 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
133 struct smatch_state *s1,
134 struct smatch_state *s2)
136 struct data_info *info1 = (struct data_info *)s1->data;
137 struct data_info *info2 = (struct data_info *)s2->data;
138 struct data_info *ret_info;
139 struct smatch_state *tmp;
140 struct range_list *value_ranges;
142 value_ranges = range_list_union(info1->value_ranges, info2->value_ranges);
143 tmp = alloc_extra_state_empty();
144 ret_info = (struct data_info *)tmp->data;
145 ret_info->value_ranges = value_ranges;
146 tmp->name = show_ranges(ret_info->value_ranges);
147 return tmp;
150 struct sm_state *__extra_pre_loop_hook_before(struct statement *iterator_pre_statement)
152 struct expression *expr;
153 char *name;
154 struct symbol *sym;
155 struct sm_state *ret = NULL;
157 if (!iterator_pre_statement)
158 return NULL;
159 if (iterator_pre_statement->type != STMT_EXPRESSION)
160 return NULL;
161 expr = iterator_pre_statement->expression;
162 if (expr->type != EXPR_ASSIGNMENT)
163 return NULL;
164 name = get_variable_from_expr(expr->left, &sym);
165 if (!name || !sym)
166 goto free;
167 ret = get_sm_state(my_id, name, sym);
168 free:
169 free_string(name);
170 return ret;
173 int __iterator_unchanged(struct sm_state *sm, struct statement *iterator)
175 struct expression *iter_expr;
176 char *name;
177 struct symbol *sym;
178 int ret = 0;
180 if (!iterator)
181 return 0;
182 if (iterator->type != STMT_EXPRESSION)
183 return 0;
184 iter_expr = iterator->expression;
185 if (iter_expr->op != SPECIAL_INCREMENT && iter_expr->op != SPECIAL_DECREMENT)
186 return 0;
187 name = get_variable_from_expr(iter_expr->unop, &sym);
188 if (!name || !sym)
189 goto free;
190 if (get_sm_state(my_id, name, sym) == sm)
191 ret = 1;
192 free:
193 free_string(name);
194 return ret;
197 void __extra_pre_loop_hook_after(struct sm_state *sm,
198 struct statement *iterator,
199 struct expression *condition)
201 struct expression *iter_expr;
202 char *name;
203 struct symbol *sym;
204 long long value;
205 int left = 0;
206 struct smatch_state *state;
207 struct data_info *dinfo;
208 long long min, max;
210 iter_expr = iterator->expression;
212 if (condition->type != EXPR_COMPARE)
213 return;
214 if (!get_value(condition->left, &value)) {
215 if (!get_value(condition->right, &value))
216 return;
217 left = 1;
219 if (left)
220 name = get_variable_from_expr(condition->left, &sym);
221 else
222 name = get_variable_from_expr(condition->right, &sym);
223 if (!name || !sym)
224 goto free;
225 if (sym != sm->sym || strcmp(name, sm->name))
226 goto free;
227 state = get_state(my_id, name, sym);
228 dinfo = (struct data_info *)state->data;
229 min = get_dinfo_min(dinfo);
230 max = get_dinfo_max(dinfo);
231 if (iter_expr->op == SPECIAL_INCREMENT && min != whole_range.min && max == whole_range.max) {
232 set_state(my_id, name, sym, alloc_extra_state(min));
233 } else if (min == whole_range.min && max != whole_range.max) {
234 set_state(my_id, name, sym, alloc_extra_state(max));
236 free:
237 free_string(name);
238 return;
241 static struct smatch_state *unmatched_state(struct sm_state *sm)
243 return extra_undefined();
246 static void match_function_call(struct expression *expr)
248 struct expression *tmp;
249 struct symbol *sym;
250 char *name;
251 int i = 0;
253 FOR_EACH_PTR(expr->args, tmp) {
254 if (tmp->type == EXPR_PREOP && tmp->op == '&') {
255 name = get_variable_from_expr(tmp->unop, &sym);
256 if (name) {
257 set_state(my_id, name, sym, extra_undefined());
259 free_string(name);
261 i++;
262 } END_FOR_EACH_PTR(tmp);
265 static void match_assign(struct expression *expr)
267 struct expression *left;
268 struct expression *right;
269 struct symbol *sym;
270 char *name;
271 long long value;
272 int known;
273 long long min = whole_range.min;
274 long long max = whole_range.max;
275 long long tmp;
276 struct range_list *rl = NULL;
278 left = strip_expr(expr->left);
279 name = get_variable_from_expr(left, &sym);
280 if (!name)
281 return;
282 right = strip_expr(expr->right);
283 while (right->type == EXPR_ASSIGNMENT && right->op == '=')
284 right = strip_expr(right->left);
286 known = get_implied_range_list(right, &rl);
287 if (expr->op == '=') {
288 if (known)
289 set_state(my_id, name, sym, alloc_extra_state_range_list(rl));
290 else
291 set_state(my_id, name, sym, extra_undefined());
292 goto free;
295 known = get_implied_value(right, &value);
296 if (expr->op == SPECIAL_ADD_ASSIGN) {
297 if (get_implied_min(left, &tmp)) {
298 if (known)
299 min = tmp + value;
300 else
301 min = tmp;
305 if (expr->op == SPECIAL_SUB_ASSIGN) {
306 if (get_implied_max(left, &tmp)) {
307 if (known)
308 max = tmp - value;
309 else
310 max = tmp;
314 set_state(my_id, name, sym, alloc_extra_state_range(min, max));
315 free:
316 free_string(name);
319 static void unop_expr(struct expression *expr)
321 struct symbol *sym;
322 char *name;
323 long long min = whole_range.min;
324 long long max = whole_range.max;
325 long long val;
327 if (expr->op == '*')
328 return;
329 if (expr->op == '(')
330 return;
332 name = get_variable_from_expr(expr->unop, &sym);
333 if (!name)
334 goto free;
335 if (expr->op == SPECIAL_INCREMENT) {
336 if (get_implied_min(expr->unop, &val))
337 min = val + 1;
339 if (expr->op == SPECIAL_DECREMENT) {
340 if (get_implied_max(expr->unop, &val))
341 max = val - 1;
343 set_state(my_id, name, sym, alloc_extra_state_range(min, max));
344 free:
345 free_string(name);
348 static void match_declarations(struct symbol *sym)
350 const char *name;
351 long long val;
353 if (sym->ident) {
354 name = sym->ident->name;
355 if (sym->initializer) {
356 if (get_value(sym->initializer, &val))
357 set_state(my_id, name, sym, alloc_extra_state(val));
358 else
359 set_state(my_id, name, sym, extra_undefined());
360 scoped_state(my_id, name, sym);
361 } else {
362 set_state(my_id, name, sym, extra_undefined());
363 scoped_state(my_id, name, sym);
368 static void match_function_def(struct symbol *sym)
370 struct symbol *arg;
372 cur_func = sym;
373 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
374 if (!arg->ident) {
375 continue;
377 set_state(my_id, arg->ident->name, arg, extra_undefined());
378 } END_FOR_EACH_PTR(arg);
381 #define VAL_SINGLE 0
382 #define VAL_MAX 1
383 #define VAL_MIN 2
385 static int get_implied_value_helper(struct expression *expr, long long *val, int what)
387 struct smatch_state *state;
388 struct symbol *sym;
389 char *name;
391 if (get_value(expr, val))
392 return 1;
394 name = get_variable_from_expr(expr, &sym);
395 if (!name)
396 return 0;
397 state = get_state(my_id, name, sym);
398 free_string(name);
399 if (!state || !state->data)
400 return 0;
401 if (what == VAL_SINGLE)
402 return get_single_value_from_range((struct data_info *)state->data, val);
403 if (what == VAL_MAX) {
404 *val = get_dinfo_max((struct data_info *)state->data);
405 if (*val == whole_range.max) /* this means just guessing */
406 return 0;
407 return 1;
409 *val = get_dinfo_min((struct data_info *)state->data);
410 if (*val == whole_range.min)
411 return 0;
412 return 1;
415 int get_implied_single_val(struct expression *expr, long long *val)
417 return get_implied_value_helper(expr, val, VAL_SINGLE);
420 int get_implied_max(struct expression *expr, long long *val)
422 return get_implied_value_helper(expr, val, VAL_MAX);
425 int get_implied_min(struct expression *expr, long long *val)
427 return get_implied_value_helper(expr, val, VAL_MIN);
430 int get_implied_single_fuzzy_max(struct expression *expr, long long *max)
432 struct sm_state *sm;
433 struct sm_state *tmp;
435 if (get_implied_max(expr, max))
436 return 1;
438 sm = get_sm_state_expr(SMATCH_EXTRA, expr);
439 if (!sm)
440 return 0;
442 *max = whole_range.min;
443 FOR_EACH_PTR(sm->possible, tmp) {
444 long long new_min;
446 new_min = get_dinfo_min((struct data_info *)tmp->state->data);
447 if (new_min > *max)
448 *max = new_min;
449 } END_FOR_EACH_PTR(tmp);
451 if (*max > whole_range.min)
452 return 1;
453 return 0;
456 static int last_stmt_val(struct statement *stmt, long long *val)
458 struct expression *expr;
460 if (!stmt)
461 return 0;
463 stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
464 if (stmt->type != STMT_EXPRESSION)
465 return 0;
466 expr = stmt->expression;
467 return get_value(expr, val);
470 static void match_comparison(struct expression *expr)
472 long long fixed;
473 char *name = NULL;
474 struct symbol *sym;
475 struct smatch_state *one_state;
476 struct smatch_state *two_state;
477 struct smatch_state *orig;
478 int left = 0;
479 int comparison = expr->op;
480 struct expression *varies = expr->right;
482 if (!get_value(expr->left, &fixed)) {
483 if (!get_value(expr->right, &fixed))
484 return;
485 varies = expr->left;
486 left = 1;
488 if (varies->op == SPECIAL_INCREMENT || varies->op == SPECIAL_DECREMENT)
489 varies = varies->unop;
490 if (varies->type == EXPR_CALL) {
491 function_comparison(comparison, varies, fixed, left);
492 return;
495 name = get_variable_from_expr(varies, &sym);
496 if (!name || !sym)
497 goto free;
499 orig = get_state(my_id, name, sym);
500 if (!orig)
501 orig = extra_undefined();
503 switch(comparison){
504 case '<':
505 case SPECIAL_UNSIGNED_LT:
506 one_state = filter_range(orig, whole_range.min, fixed - 1);
507 two_state = filter_range(orig, fixed, whole_range.max);
508 if (left)
509 set_true_false_states(my_id, name, sym, two_state, one_state);
510 else
511 set_true_false_states(my_id, name, sym, one_state, two_state);
512 return;
513 case SPECIAL_UNSIGNED_LTE:
514 case SPECIAL_LTE:
515 one_state = filter_range(orig, whole_range.min, fixed);
516 two_state = filter_range(orig, fixed + 1, whole_range.max);
517 if (left)
518 set_true_false_states(my_id, name, sym, two_state, one_state);
519 else
520 set_true_false_states(my_id, name, sym, one_state, two_state);
521 return;
522 case SPECIAL_EQUAL:
523 // todo. print a warning here for impossible conditions.
524 one_state = alloc_extra_state(fixed);
525 two_state = filter_range(orig, fixed, fixed);
526 set_true_false_states(my_id, name, sym, one_state, two_state);
527 return;
528 case SPECIAL_UNSIGNED_GTE:
529 case SPECIAL_GTE:
530 one_state = filter_range(orig, whole_range.min, fixed - 1);
531 two_state = filter_range(orig, fixed, whole_range.max);
532 if (left)
533 set_true_false_states(my_id, name, sym, one_state, two_state);
534 else
535 set_true_false_states(my_id, name, sym, two_state, one_state);
536 return;
537 case '>':
538 case SPECIAL_UNSIGNED_GT:
539 one_state = filter_range(orig, whole_range.min, fixed);
540 two_state = filter_range(orig, fixed + 1, whole_range.max);
541 if (left)
542 set_true_false_states(my_id, name, sym, one_state, two_state);
543 else
544 set_true_false_states(my_id, name, sym, two_state, one_state);
545 return;
546 case SPECIAL_NOTEQUAL:
547 one_state = alloc_extra_state(fixed);
548 two_state = filter_range(orig, fixed, fixed);
549 set_true_false_states(my_id, name, sym, two_state, one_state);
550 return;
551 default:
552 sm_msg("unhandled comparison %d\n", comparison);
553 return;
555 return;
556 free:
557 free_string(name);
560 /* this is actually hooked from smatch_implied.c... it's hacky, yes */
561 void __extra_match_condition(struct expression *expr)
563 struct symbol *sym;
564 char *name;
565 struct smatch_state *pre_state;
566 struct smatch_state *true_state;
567 struct smatch_state *false_state;
569 expr = strip_expr(expr);
570 switch(expr->type) {
571 case EXPR_CALL:
572 function_comparison(SPECIAL_NOTEQUAL, expr, 0, 1);
573 return;
574 case EXPR_PREOP:
575 case EXPR_SYMBOL:
576 case EXPR_DEREF:
577 name = get_variable_from_expr(expr, &sym);
578 if (!name)
579 return;
580 pre_state = get_state(my_id, name, sym);
581 true_state = add_filter(pre_state, 0);
582 false_state = alloc_extra_state(0);
583 set_true_false_states(my_id, name, sym, true_state, false_state);
584 free_string(name);
585 return;
586 case EXPR_COMPARE:
587 match_comparison(expr);
588 return;
589 case EXPR_ASSIGNMENT:
590 __extra_match_condition(expr->left);
591 return;
595 /* returns 1 if it is not possible for expr to be value, otherwise returns 0 */
596 int implied_not_equal(struct expression *expr, long long val)
598 char *name;
599 struct symbol *sym;
600 struct smatch_state *state;
601 int ret = 0;
603 name = get_variable_from_expr(expr, &sym);
604 if (!name || !sym)
605 goto exit;
606 state = get_state(my_id, name, sym);
607 if (!state || !state->data)
608 goto exit;
609 ret = !possibly_false(SPECIAL_NOTEQUAL, (struct data_info *)state->data, val, 1);
610 exit:
611 free_string(name);
612 return ret;
615 int known_condition_true(struct expression *expr)
617 long long tmp;
619 if (!expr)
620 return 0;
622 if (get_value(expr, &tmp) && tmp)
623 return 1;
625 expr = strip_expr(expr);
626 switch(expr->type) {
627 case EXPR_PREOP:
628 if (expr->op == '!') {
629 if (known_condition_false(expr->unop))
630 return 1;
631 break;
633 break;
634 default:
635 break;
637 return 0;
640 int known_condition_false(struct expression *expr)
642 if (!expr)
643 return 0;
645 if (is_zero(expr))
646 return 1;
648 switch(expr->type) {
649 case EXPR_PREOP:
650 if (expr->op == '!') {
651 if (known_condition_true(expr->unop))
652 return 1;
653 break;
655 break;
656 default:
657 break;
659 return 0;
662 static int do_comparison_range(struct expression *expr)
664 struct symbol *sym;
665 char *name;
666 struct smatch_state *state;
667 long long value;
668 int left = 0;
669 int poss_true, poss_false;
671 if (!get_value(expr->left, &value)) {
672 if (!get_value(expr->right, &value))
673 return 3;
674 left = 1;
676 if (left)
677 name = get_variable_from_expr(expr->left, &sym);
678 else
679 name = get_variable_from_expr(expr->right, &sym);
680 if (!name || !sym)
681 goto free;
682 state = get_state(SMATCH_EXTRA, name, sym);
683 if (!state)
684 goto free;
685 poss_true = possibly_true(expr->op, (struct data_info *)state->data, value, left);
686 poss_false = possibly_false(expr->op, (struct data_info *)state->data, value, left);
687 if (!poss_true && !poss_false)
688 return 0;
689 if (poss_true && !poss_false)
690 return 1;
691 if (!poss_true && poss_false)
692 return 2;
693 if (poss_true && poss_false)
694 return 3;
695 free:
696 free_string(name);
697 return 3;
700 int implied_condition_true(struct expression *expr)
702 struct statement *stmt;
703 long long tmp;
704 long long val;
706 if (!expr)
707 return 0;
709 if (get_value(expr, &tmp) && tmp)
710 return 1;
712 expr = strip_expr(expr);
713 switch(expr->type) {
714 case EXPR_COMPARE:
715 if (do_comparison_range(expr) == 1)
716 return 1;
717 break;
718 case EXPR_PREOP:
719 if (expr->op == '!') {
720 if (implied_condition_false(expr->unop))
721 return 1;
722 break;
724 stmt = get_block_thing(expr);
725 if (last_stmt_val(stmt, &val) && val == 1)
726 return 1;
727 break;
728 default:
729 if (implied_not_equal(expr, 0) == 1)
730 return 1;
731 break;
733 return 0;
736 int implied_condition_false(struct expression *expr)
738 struct statement *stmt;
739 struct expression *tmp;
740 long long val;
742 if (!expr)
743 return 0;
745 if (is_zero(expr))
746 return 1;
748 switch(expr->type) {
749 case EXPR_COMPARE:
750 if (do_comparison_range(expr) == 2)
751 return 1;
752 case EXPR_PREOP:
753 if (expr->op == '!') {
754 if (implied_condition_true(expr->unop))
755 return 1;
756 break;
758 stmt = get_block_thing(expr);
759 if (last_stmt_val(stmt, &val) && val == 0)
760 return 1;
761 tmp = strip_expr(expr);
762 if (tmp != expr)
763 return implied_condition_false(tmp);
764 break;
765 default:
766 if (get_implied_value(expr, &val) && val == 0)
767 return 1;
768 break;
770 return 0;
773 int get_implied_range_list(struct expression *expr, struct range_list **rl)
775 long long val;
776 struct smatch_state *state;
778 expr = strip_expr(expr);
780 state = get_state_expr(my_id, expr);
781 if (state) {
782 *rl = clone_range_list(((struct data_info *)state->data)->value_ranges);
783 return 1;
786 if (get_implied_value(expr, &val)) {
787 *rl = NULL;
788 add_range(rl, val, val);
789 return 1;
792 if (expr->type == EXPR_BINOP && expr->op == '%') {
793 if (!get_implied_value(expr->right, &val))
794 return 0;
795 *rl = NULL;
796 add_range(rl, 0, val - 1);
797 return 1;
800 return 0;
803 void register_smatch_extra(int id)
805 my_id = id;
806 add_merge_hook(my_id, &merge_func);
807 add_unmatched_state_hook(my_id, &unmatched_state);
808 add_hook(&unop_expr, OP_HOOK);
809 add_hook(&match_function_def, FUNC_DEF_HOOK);
810 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
811 add_hook(&match_assign, ASSIGNMENT_HOOK);
812 add_hook(&match_declarations, DECLARATION_HOOK);
814 if (option_project == PROJ_KERNEL) {
815 /* I don't know how to test for the ATTRIB_NORET attribute. :( */
816 add_function_hook("panic", &__match_nullify_path_hook, NULL);
817 add_function_hook("do_exit", &__match_nullify_path_hook, NULL);
818 add_function_hook("complete_and_exit", &__match_nullify_path_hook, NULL);
819 add_function_hook("__module_put_and_exit", &__match_nullify_path_hook, NULL);
820 add_function_hook("do_group_exit", &__match_nullify_path_hook, NULL);