2 * sparse/check_param_range.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
11 #include "smatch_extra.h"
12 #include "smatch_slist.h"
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
;
26 FOR_EACH_PTR_REVERSE(big_statement_stack
, tmp
) {
29 } END_FOR_EACH_PTR_REVERSE(tmp
);
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)
44 static int is_error_value(struct expression
*ret_value
)
52 if (ret_value
->type
!= EXPR_PREOP
|| ret_value
->op
!= '-')
55 if (!get_value(ret_value
, &val
))
57 if (val
< -4095 || val
>= 0)
60 name
= pos_ident(ret_value
->unop
->pos
);
68 static struct expression
*get_param(struct expression
*expr
)
73 expr
= strip_expr(expr
);
74 if (!expr
|| expr
->type
!= EXPR_SYMBOL
)
78 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
81 } END_FOR_EACH_PTR(tmp
);
86 static int get_param_num(struct expression
*expr
)
92 expr
= strip_expr(expr
);
93 if (!expr
|| expr
->type
!= EXPR_SYMBOL
)
98 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
102 } END_FOR_EACH_PTR(tmp
);
107 static void add_param_constraint(int idx
, struct range_list
*rl
)
109 if (!param_constraints
[idx
]) {
110 param_constraints
[idx
] = rl
;
113 param_constraints
[idx
] = range_list_union(param_constraints
[idx
], rl
);
116 static void handle_condition(struct expression
*expr
)
119 struct expression
*param
;
120 struct state_list
*slist
= NULL
;
124 expr
= strip_expr(expr
);
128 switch (expr
->type
) {
130 if (expr
->op
== SPECIAL_LOGICAL_OR
) {
131 handle_condition(expr
->left
);
132 handle_condition(expr
->right
);
136 param
= get_param(expr
->left
);
139 param
= get_param(expr
->right
);
144 if (expr
->op
== '!') {
145 param
= get_param(expr
->unop
);
151 param
= get_param(expr
);
159 name
= get_variable_from_expr(param
, &sym
);
163 __push_fake_cur_slist();
164 __split_whole_condition(expr
);
166 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
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();
184 static void match_return(struct expression
*ret_value
)
186 struct statement
*stmt
;
188 if (have_returned_zero
)
190 if (possibly_true(ret_value
, SPECIAL_EQUAL
, zero_expr())) {
191 have_returned_zero
= 1;
195 if (!on_main_path(ret_value
)) /* should we just set have_returned_zero here? */
198 if (!is_error_value(ret_value
))
200 stmt
= prev_statement();
201 if (!stmt
|| stmt
->type
!= STMT_IF
)
203 handle_condition(stmt
->if_conditional
);
206 static void match_end_func(struct symbol
*sym
)
210 for (i
= 0; i
< ARRAY_SIZE(param_constraints
); i
++) {
211 if (!param_constraints
[i
])
213 if (is_whole_range_rl(param_constraints
[i
]))
215 sm_msg("info: param %d range '%s' implies error return",
216 i
, show_ranges(param_constraints
[i
]));
219 have_returned_zero
= 0;
220 for (i
= 0; i
< ARRAY_SIZE(param_constraints
); i
++)
221 param_constraints
[i
] = NULL
;
224 void check_param_range(int id
)
226 if (!option_info
|| option_project
!= PROJ_KERNEL
)
230 add_hook(&match_return
, RETURN_HOOK
);
231 add_hook(&match_end_func
, END_FUNC_HOOK
);