extra, modification_hooks: set "*p" to unknown if we call "function(p)"
[smatch.git] / check_bool_implications.c
blob6c2fe70bb1c83a48e9c96074ae0d6c2d40533754
1 /*
2 * sparse/check_bool_implications.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_extra.h"
12 #include "smatch_slist.h"
14 static int my_id;
16 static struct state_list_stack *true_stack;
17 static struct state_list_stack *false_stack;
19 static int returns_other;
21 static int non_bool(struct expression *expr)
23 if (possibly_true(expr, '<', zero_expr()))
24 return 1;
25 if (possibly_true(expr, '>', value_expr(1)))
26 return 1;
27 return 0;
30 static void handle_condition_return(struct expression *expr)
32 struct state_list *slist;
33 int was_final_pass;
35 was_final_pass = final_pass;
36 final_pass = 0;
37 __push_fake_cur_slist();
38 __split_whole_condition(expr);
39 push_slist(&true_stack, clone_slist(__get_cur_slist()));
40 __push_true_states();
41 __use_false_states();
42 push_slist(&false_stack, clone_slist(__get_cur_slist()));
43 __merge_true_states();
44 slist = __pop_fake_cur_slist();
45 final_pass = was_final_pass;
46 free_slist(&slist);
49 static void match_return(struct expression *ret_value)
51 sval_t sval;
53 if (returns_other || !ret_value)
54 return;
56 if (non_bool(ret_value)) {
57 returns_other = 1;
58 return;
61 if (get_implied_value(ret_value, &sval) && sval.value == 1) {
62 push_slist(&true_stack, clone_slist(__get_cur_slist()));
63 return;
66 if (get_implied_value(ret_value, &sval) && sval.value == 0) {
67 push_slist(&false_stack, clone_slist(__get_cur_slist()));
68 return;
71 handle_condition_return(ret_value);
74 static void print_implications(struct symbol *sym, int param,
75 struct state_list *true_states,
76 struct state_list *false_states)
78 struct smatch_state *true_state;
79 struct smatch_state *false_state;
81 if (!sym->ident)
82 return;
84 true_state = get_state_slist(true_states, SMATCH_EXTRA, sym->ident->name, sym);
85 false_state = get_state_slist(false_states, SMATCH_EXTRA, sym->ident->name, sym);
87 if (!true_state || !false_state)
88 return;
90 if (rl_equiv(estate_rl(true_state), estate_rl(false_state)))
91 return;
93 sm_msg("info: bool_return_implication \"1\" %d \"%s\" %s", param,
94 show_rl(estate_rl(true_state)), global_static());
95 sm_msg("info: bool_return_implication \"0\" %d \"%s\" %s", param,
96 show_rl(estate_rl(false_state)), global_static());
99 static void cleanup(void)
101 free_stack_and_slists(&true_stack);
102 free_stack_and_slists(&false_stack);
103 returns_other = 0;
106 static void match_end_func(struct symbol *sym)
108 struct state_list *merged_true = NULL;
109 struct state_list *merged_false = NULL;
110 struct state_list *tmp;
111 struct symbol *param_sym;
112 int i;
114 if (returns_other) {
115 cleanup();
116 return;
119 FOR_EACH_PTR(true_stack, tmp) {
120 merge_slist(&merged_true, tmp);
121 } END_FOR_EACH_PTR(tmp);
123 FOR_EACH_PTR(false_stack, tmp) {
124 merge_slist(&merged_false, tmp);
125 } END_FOR_EACH_PTR(tmp);
127 i = 0;
128 FOR_EACH_PTR(sym->ctype.base_type->arguments, param_sym) {
129 print_implications(param_sym, i, merged_true, merged_false);
130 i++;
131 } END_FOR_EACH_PTR(param_sym);
134 free_slist(&merged_true);
135 free_slist(&merged_false);
137 cleanup();
140 void check_bool_implications(int id)
142 if (!option_info)
143 return;
145 my_id = id;
146 add_hook(&match_return, RETURN_HOOK);
147 add_hook(&match_end_func, END_FUNC_HOOK);