extra: revert the mod_expr changes for modify expression hooks
[smatch.git] / smatch_integer_overflow.c
blob96fd25f4f1b2069118beff28ee3a3e5e86c3b4cc
1 /*
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
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static int my_id;
23 static int link_id;
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");
32 state->data = expr;
33 return state;
36 static char *save_links(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
38 struct var_sym *vs;
39 char *name;
41 name = expr_to_chunk_sym_vsl(expr, sym, vsl);
42 if (!name || !*vsl) {
43 free_string(name);
44 return NULL;
47 FOR_EACH_PTR(*vsl, vs) {
48 store_link(link_id, vs->var, vs->sym, name, *sym);
49 } END_FOR_EACH_PTR(vs);
51 return name;
54 static void match_divide(struct expression *expr)
56 struct expression *left, *right, *binop;
57 struct symbol *type;
58 char *name;
59 struct symbol *sym;
60 struct var_sym_list *vsl;
61 sval_t max;
63 if (expr->type != EXPR_COMPARE)
64 return;
65 if (expr->op != '>' && expr->op != SPECIAL_UNSIGNED_GT &&
66 expr->op != SPECIAL_GTE && expr->op != SPECIAL_UNSIGNED_GTE)
67 return;
69 left = strip_parens(expr->left);
70 right = strip_parens(expr->right);
72 if (right->type != EXPR_BINOP || right->op != '/')
73 return;
74 if (!get_value(right->left, &max))
75 return;
76 if (max.value != INT_MAX && max.value != UINT_MAX &&
77 max.value != LLONG_MAX && max.uvalue != ULLONG_MAX)
78 return;
80 type = get_type(expr);
81 if (!type)
82 return;
83 if (type_bits(type) != 32 && type_bits(type) != 64)
84 return;
87 binop = binop_expression(left, '*', right->right);
89 name = save_links(binop, &sym, &vsl);
90 if (!name)
91 return;
92 set_true_false_states(my_id, name, sym, NULL, safe_state(binop));
93 free_string(name);
96 static void match_overflow_to_less_than(struct expression *expr)
98 struct expression *left, *right;
99 struct symbol *type;
100 char *name;
101 struct symbol *sym;
102 struct var_sym_list *vsl;
104 if (expr->type != EXPR_COMPARE)
105 return;
106 if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
107 return;
109 left = strip_parens(expr->left);
110 right = strip_parens(expr->right);
112 if (left->op != '+')
113 return;
115 type = get_type(expr);
116 if (!type)
117 return;
118 if (type_bits(type) != 32 && type_bits(type) != 64)
119 return;
121 if (!expr_equiv(left->left, right) && !expr_equiv(left->right, right))
122 return;
124 name = save_links(left, &sym, &vsl);
125 if (!name)
126 return;
127 set_true_false_states(my_id, name, sym, NULL, safe_state(left));
128 free_string(name);
131 static void match_condition(struct expression *expr)
133 match_overflow_to_less_than(expr);
134 match_divide(expr);
137 int can_integer_overflow(struct symbol *type, struct expression *expr)
139 int op;
140 sval_t lmax, rmax, res;
142 if (!type)
143 type = &int_ctype;
145 expr = strip_expr(expr);
147 if (expr->type == EXPR_ASSIGNMENT) {
148 switch(expr->op) {
149 case SPECIAL_MUL_ASSIGN:
150 op = '*';
151 break;
152 case SPECIAL_ADD_ASSIGN:
153 op = '+';
154 break;
155 case SPECIAL_SHL_ASSIGN:
156 op = SPECIAL_LEFTSHIFT;
157 break;
158 default:
159 return 0;
161 } else if (expr->type == EXPR_BINOP) {
162 if (expr->op != '*' && expr->op != '+' && expr->op != SPECIAL_LEFTSHIFT)
163 return 0;
164 op = expr->op;
165 } else {
166 return 0;
169 get_absolute_max(expr->left, &lmax);
170 get_absolute_max(expr->right, &rmax);
172 if (sval_binop_overflows(lmax, op, rmax))
173 return 1;
175 res = sval_binop(lmax, op, rmax);
176 if (sval_cmp(res, sval_type_max(type)) > 0)
177 return 1;
178 return 0;
181 int can_integer_overflow_expr(struct expression *expr)
183 struct symbol *type;
184 struct smatch_state *state;
185 char *name;
186 struct symbol *sym;
187 int ret = 1;
189 type = get_type(expr);
190 if (!type)
191 return 0;
193 if (!can_integer_overflow(type, expr))
194 return 0;
196 name = expr_to_known_chunk_sym(expr, &sym);
197 if (!name || !sym)
198 goto free;
200 state = get_state(my_id, name, sym);
201 if (state && state->data)
202 ret = 0;
203 free:
204 free_string(name);
205 return ret;
208 static int get_arg_nr(struct expression *call, struct expression *expr)
210 struct expression *arg;
211 int i;
213 i = -1;
214 FOR_EACH_PTR(call->args, arg) {
215 i++;
216 if (expr_equiv(arg, expr))
217 return i;
218 } END_FOR_EACH_PTR(arg);
220 return -1;
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;
226 struct var_sym *vs;
227 struct smatch_state *state;
228 struct expression *expr;
229 int left = -1;
230 int right = -1;
232 FOR_EACH_PTR(vsl, vs) {
233 state = get_state(my_id, vs->var, vs->sym);
234 if (!state || !state->data)
235 continue;
237 expr = state->data;
239 if (expr_equiv(arg, expr->left)) {
240 left = nr;
241 right = get_arg_nr(call, expr->right);
242 } else if (expr_equiv(arg, expr->right)) {
243 left = get_arg_nr(call, expr->left);
244 right = nr;
247 if (left == -1 || right == -1)
248 continue;
250 left = -1;
251 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;
260 int i;
262 i = -1;
263 FOR_EACH_PTR(call->args, arg) {
264 i++;
266 link = get_sm_state_expr(link_id, arg);
267 if (!link)
268 continue;
270 if (get_state_stree(done, my_id, link->state->name, NULL))
271 continue;
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);
277 free_stree(&done);
280 void register_integer_overflow(int id)
282 my_id = 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)
290 link_id = id;
291 set_up_link_functions(my_id, link_id);