db: print return_states information in a more detailed way
[smatch.git] / check_param_range.c
blob84683f626aa05a56625f249cef2f704c1eaa1c88
1 /*
2 * sparse/check_param_range.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 int have_returned_zero;
17 static struct range_list *param_constraints[16];
20 static struct statement *prev_statement(void)
22 struct statement *tmp;
23 int i;
25 i = 0;
26 FOR_EACH_PTR_REVERSE(big_statement_stack, tmp) {
27 if (i++ == 1)
28 return tmp;
29 } END_FOR_EACH_PTR_REVERSE(tmp);
30 return NULL;
34 * on_main_path() is supposed to check for nesting. As a hack it just counts
35 * the current indent level.
37 static int on_main_path(struct expression *expr)
39 if (expr->pos.pos == 24)
40 return 1;
41 return 0;
44 static int is_error_value(struct expression *ret_value)
46 sval_t sval;
47 char *name;
49 if (!ret_value)
50 return 0;
52 if (ret_value->type != EXPR_PREOP || ret_value->op != '-')
53 return 0;
55 if (!get_value(ret_value, &sval))
56 return 0;
57 if (sval.value < -4095 || sval.value >= 0)
58 return 0;
60 name = pos_ident(ret_value->unop->pos);
61 if (!name)
62 return 0;
63 if (name[0] == 'E')
64 return 1;
65 return 0;
68 static struct expression *get_param(struct expression *expr)
70 struct symbol *sym;
71 struct symbol *tmp;
73 expr = strip_expr(expr);
74 if (!expr || expr->type != EXPR_SYMBOL)
75 return 0;
77 sym = expr->symbol;
78 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
79 if (tmp == sym)
80 return expr;
81 } END_FOR_EACH_PTR(tmp);
83 return NULL;
86 static int get_param_num(struct expression *expr)
88 struct symbol *sym;
89 struct symbol *tmp;
90 int i;
92 expr = strip_expr(expr);
93 if (!expr || expr->type != EXPR_SYMBOL)
94 return -1;
96 sym = expr->symbol;
97 i = 0;
98 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
99 if (tmp == sym)
100 return i;
101 i++;
102 } END_FOR_EACH_PTR(tmp);
104 return -1;
107 static void add_param_constraint(int idx, struct range_list *rl)
109 if (!param_constraints[idx]) {
110 param_constraints[idx] = rl;
111 return;
113 param_constraints[idx] = range_list_union(param_constraints[idx], rl);
116 static void handle_condition(struct expression *expr)
118 struct sm_state *sm;
119 struct expression *param;
120 struct state_list *slist = NULL;
121 char *name;
122 struct symbol *sym;
124 expr = strip_expr(expr);
125 if (!expr)
126 return;
128 switch (expr->type) {
129 case EXPR_LOGICAL:
130 if (expr->op == SPECIAL_LOGICAL_OR) {
131 handle_condition(expr->left);
132 handle_condition(expr->right);
134 return;
135 case EXPR_COMPARE:
136 param = get_param(expr->left);
137 if (param)
138 break;
139 param = get_param(expr->right);
140 if (param)
141 break;
142 return;
143 case EXPR_PREOP:
144 if (expr->op == '!') {
145 param = get_param(expr->unop);
146 if (param)
147 break;
149 return;
150 case EXPR_SYMBOL:
151 param = get_param(expr);
152 if (param)
153 break;
154 return;
155 default:
156 return;
159 name = get_variable_from_expr(param, &sym);
160 if (!name || !sym)
161 goto free;
163 __push_fake_cur_slist();
164 __split_whole_condition(expr);
166 sm = get_sm_state(SMATCH_EXTRA, name, sym);
167 if (sm) {
168 int num;
170 num = get_param_num(param);
171 add_param_constraint(num, estate_ranges(sm->state));
174 __push_true_states();
175 __use_false_states();
176 __merge_true_states();
177 slist = __pop_fake_cur_slist();
179 free:
180 free_string(name);
181 free_slist(&slist);
184 static void match_return(struct expression *ret_value)
186 struct statement *stmt;
188 if (have_returned_zero)
189 return;
190 if (possibly_true(ret_value, SPECIAL_EQUAL, zero_expr())) {
191 have_returned_zero = 1;
192 return;
195 if (!on_main_path(ret_value)) /* should we just set have_returned_zero here? */
196 return;
198 if (!is_error_value(ret_value))
199 return;
200 stmt = prev_statement();
201 if (!stmt || stmt->type != STMT_IF)
202 return;
203 handle_condition(stmt->if_conditional);
206 static void match_end_func(struct symbol *sym)
208 int i;
210 for (i = 0; i < ARRAY_SIZE(param_constraints); i++) {
211 if (!param_constraints[i])
212 continue;
213 if (is_whole_range_rl(param_constraints[i]))
214 continue;
215 sm_msg("info: %s param %d range '%s' implies error return %s",
216 global_static(), i, show_ranges(param_constraints[i]),
217 global_static());
220 have_returned_zero = 0;
221 for (i = 0; i < ARRAY_SIZE(param_constraints); i++)
222 param_constraints[i] = NULL;
225 void check_param_range(int id)
227 if (!option_info || option_project != PROJ_KERNEL)
228 return;
230 my_id = id;
231 add_hook(&match_return, RETURN_HOOK);
232 add_hook(&match_end_func, END_FUNC_HOOK);