2 * Copyright (C) 2015 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
25 static struct smatch_state
*safe_state(struct expression
*expr
)
27 struct smatch_state
*state
;
29 state
= __alloc_smatch_state(0);
30 expr
= strip_expr(expr
);
31 state
->name
= alloc_sname("safe");
36 static char *save_links(struct expression
*expr
, struct symbol
**sym
, struct var_sym_list
**vsl
)
41 name
= expr_to_chunk_sym_vsl(expr
, sym
, vsl
);
47 FOR_EACH_PTR(*vsl
, vs
) {
48 store_link(link_id
, vs
->var
, vs
->sym
, name
, *sym
);
49 } END_FOR_EACH_PTR(vs
);
54 static void match_divide(struct expression
*expr
)
56 struct expression
*left
, *right
, *binop
;
60 struct var_sym_list
*vsl
;
63 if (expr
->type
!= EXPR_COMPARE
)
65 if (expr
->op
!= '>' && expr
->op
!= SPECIAL_UNSIGNED_GT
&&
66 expr
->op
!= SPECIAL_GTE
&& expr
->op
!= SPECIAL_UNSIGNED_GTE
)
69 left
= strip_parens(expr
->left
);
70 right
= strip_parens(expr
->right
);
72 if (right
->type
!= EXPR_BINOP
|| right
->op
!= '/')
74 if (!get_value(right
->left
, &max
))
76 if (max
.value
!= INT_MAX
&& max
.value
!= UINT_MAX
&&
77 max
.value
!= LLONG_MAX
&& max
.uvalue
!= ULLONG_MAX
)
80 type
= get_type(expr
);
83 if (type_bits(type
) != 32 && type_bits(type
) != 64)
87 binop
= binop_expression(left
, '*', right
->right
);
89 name
= save_links(binop
, &sym
, &vsl
);
92 set_true_false_states(my_id
, name
, sym
, NULL
, safe_state(binop
));
96 static void match_overflow_to_less_than(struct expression
*expr
)
98 struct expression
*left
, *right
;
102 struct var_sym_list
*vsl
;
104 if (expr
->type
!= EXPR_COMPARE
)
106 if (expr
->op
!= '<' && expr
->op
!= SPECIAL_UNSIGNED_LT
)
109 left
= strip_parens(expr
->left
);
110 right
= strip_parens(expr
->right
);
115 type
= get_type(expr
);
118 if (type_bits(type
) != 32 && type_bits(type
) != 64)
121 if (!expr_equiv(left
->left
, right
) && !expr_equiv(left
->right
, right
))
124 name
= save_links(left
, &sym
, &vsl
);
127 set_true_false_states(my_id
, name
, sym
, NULL
, safe_state(left
));
131 static void match_condition(struct expression
*expr
)
133 match_overflow_to_less_than(expr
);
137 int can_integer_overflow(struct symbol
*type
, struct expression
*expr
)
140 sval_t lmax
, rmax
, res
;
145 expr
= strip_expr(expr
);
147 if (expr
->type
== EXPR_ASSIGNMENT
) {
149 case SPECIAL_MUL_ASSIGN
:
152 case SPECIAL_ADD_ASSIGN
:
155 case SPECIAL_SHL_ASSIGN
:
156 op
= SPECIAL_LEFTSHIFT
;
161 } else if (expr
->type
== EXPR_BINOP
) {
162 if (expr
->op
!= '*' && expr
->op
!= '+' && expr
->op
!= SPECIAL_LEFTSHIFT
)
169 get_absolute_max(expr
->left
, &lmax
);
170 get_absolute_max(expr
->right
, &rmax
);
172 if (sval_binop_overflows(lmax
, op
, rmax
))
175 res
= sval_binop(lmax
, op
, rmax
);
176 if (sval_cmp(res
, sval_type_max(type
)) > 0)
181 int can_integer_overflow_expr(struct expression
*expr
)
184 struct smatch_state
*state
;
189 type
= get_type(expr
);
193 if (!can_integer_overflow(type
, expr
))
196 name
= expr_to_known_chunk_sym(expr
, &sym
);
200 state
= get_state(my_id
, name
, sym
);
201 if (state
&& state
->data
)
208 static int get_arg_nr(struct expression
*call
, struct expression
*expr
)
210 struct expression
*arg
;
214 FOR_EACH_PTR(call
->args
, arg
) {
216 if (expr_equiv(arg
, expr
))
218 } END_FOR_EACH_PTR(arg
);
223 static void check_links(struct expression
*call
, struct expression
*arg
, int nr
, struct sm_state
*sm
, void *_vsl
)
225 struct var_sym_list
*vsl
= _vsl
;
227 struct smatch_state
*state
;
228 struct expression
*expr
;
232 FOR_EACH_PTR(vsl
, vs
) {
233 state
= get_state(my_id
, vs
->var
, vs
->sym
);
234 if (!state
|| !state
->data
)
239 if (expr_equiv(arg
, expr
->left
)) {
241 right
= get_arg_nr(call
, expr
->right
);
242 } else if (expr_equiv(arg
, expr
->right
)) {
243 left
= get_arg_nr(call
, expr
->left
);
247 if (left
== -1 || right
== -1)
252 } END_FOR_EACH_PTR(vs
);
255 static void match_call_info(struct expression
*call
)
257 struct expression
*arg
;
258 struct sm_state
*link
;
259 struct stree
*done
= NULL
;
263 FOR_EACH_PTR(call
->args
, arg
) {
266 link
= get_sm_state_expr(link_id
, arg
);
270 if (get_state_stree(done
, my_id
, link
->state
->name
, NULL
))
272 // set_state_stree(&done, my_id, link->state->name, NULL, &undefined);
274 check_links(call
, arg
, i
, link
, link
->state
->data
);
275 } END_FOR_EACH_PTR(arg
);
280 void register_integer_overflow(int id
)
283 set_dynamic_states(my_id
);
284 add_hook(&match_condition
, CONDITION_HOOK
);
285 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
288 void register_integer_overflow_links(int id
)
291 set_up_link_functions(my_id
, link_id
);