Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_integer_overflow.c
+++ new/usr/src/tools/smatch/src/smatch_integer_overflow.c
1 1 /*
2 2 * Copyright (C) 2015 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 #include "smatch.h"
19 19 #include "smatch_slist.h"
20 20 #include "smatch_extra.h"
21 21
22 22 static int my_id;
23 23 static int link_id;
24 24
25 25 static struct smatch_state *safe_state(struct expression *expr)
26 26 {
27 27 struct smatch_state *state;
28 28
29 29 state = __alloc_smatch_state(0);
30 30 expr = strip_expr(expr);
31 31 state->name = alloc_sname("safe");
32 32 state->data = expr;
33 33 return state;
34 34 }
35 35
36 36 static char *save_links(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
37 37 {
38 38 struct var_sym *vs;
39 39 char *name;
40 40
41 41 name = expr_to_chunk_sym_vsl(expr, sym, vsl);
42 42 if (!name || !*vsl) {
43 43 free_string(name);
44 44 return NULL;
45 45 }
46 46
47 47 FOR_EACH_PTR(*vsl, vs) {
48 48 store_link(link_id, vs->var, vs->sym, name, *sym);
49 49 } END_FOR_EACH_PTR(vs);
50 50
51 51 return name;
52 52 }
53 53
54 54 static void match_divide(struct expression *expr)
55 55 {
56 56 struct expression *left, *right, *binop;
57 57 struct symbol *type;
58 58 char *name;
59 59 struct symbol *sym;
60 60 struct var_sym_list *vsl;
61 61 sval_t max;
62 62
63 63 if (expr->type != EXPR_COMPARE)
64 64 return;
65 65 if (expr->op != '>' && expr->op != SPECIAL_UNSIGNED_GT &&
66 66 expr->op != SPECIAL_GTE && expr->op != SPECIAL_UNSIGNED_GTE)
67 67 return;
68 68
69 69 left = strip_parens(expr->left);
70 70 right = strip_parens(expr->right);
71 71
72 72 if (right->type != EXPR_BINOP || right->op != '/')
73 73 return;
74 74 if (!get_value(right->left, &max))
75 75 return;
76 76 if (max.value != INT_MAX && max.value != UINT_MAX &&
77 77 max.value != LLONG_MAX && max.uvalue != ULLONG_MAX)
78 78 return;
79 79
80 80 type = get_type(expr);
81 81 if (!type)
82 82 return;
83 83 if (type_bits(type) != 32 && type_bits(type) != 64)
84 84 return;
85 85
86 86
87 87 binop = binop_expression(left, '*', right->right);
88 88
89 89 name = save_links(binop, &sym, &vsl);
90 90 if (!name)
91 91 return;
92 92 set_true_false_states(my_id, name, sym, NULL, safe_state(binop));
93 93 free_string(name);
94 94 }
95 95
96 96 static void match_overflow_to_less_than(struct expression *expr)
97 97 {
98 98 struct expression *left, *right;
99 99 struct symbol *type;
100 100 char *name;
101 101 struct symbol *sym;
102 102 struct var_sym_list *vsl;
103 103
104 104 if (expr->type != EXPR_COMPARE)
105 105 return;
106 106 if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
107 107 return;
108 108
109 109 left = strip_parens(expr->left);
110 110 right = strip_parens(expr->right);
111 111
112 112 if (left->op != '+')
113 113 return;
114 114
115 115 type = get_type(expr);
116 116 if (!type)
117 117 return;
118 118 if (type_bits(type) != 32 && type_bits(type) != 64)
119 119 return;
120 120
121 121 if (!expr_equiv(left->left, right) && !expr_equiv(left->right, right))
122 122 return;
123 123
124 124 name = save_links(left, &sym, &vsl);
125 125 if (!name)
126 126 return;
127 127 set_true_false_states(my_id, name, sym, NULL, safe_state(left));
128 128 free_string(name);
129 129 }
130 130
131 131 static void match_condition(struct expression *expr)
132 132 {
133 133 match_overflow_to_less_than(expr);
134 134 match_divide(expr);
135 135 }
136 136
137 137 int can_integer_overflow(struct symbol *type, struct expression *expr)
138 138 {
139 139 int op;
140 140 sval_t lmax, rmax, res;
141 141
142 142 if (!type)
143 143 type = &int_ctype;
144 144
145 145 expr = strip_expr(expr);
146 146
147 147 if (expr->type == EXPR_ASSIGNMENT) {
148 148 switch(expr->op) {
149 149 case SPECIAL_MUL_ASSIGN:
150 150 op = '*';
151 151 break;
152 152 case SPECIAL_ADD_ASSIGN:
153 153 op = '+';
154 154 break;
155 155 case SPECIAL_SHL_ASSIGN:
156 156 op = SPECIAL_LEFTSHIFT;
157 157 break;
158 158 default:
159 159 return 0;
160 160 }
161 161 } else if (expr->type == EXPR_BINOP) {
162 162 if (expr->op != '*' && expr->op != '+' && expr->op != SPECIAL_LEFTSHIFT)
163 163 return 0;
164 164 op = expr->op;
165 165 } else {
166 166 return 0;
167 167 }
168 168
169 169 get_absolute_max(expr->left, &lmax);
170 170 get_absolute_max(expr->right, &rmax);
171 171
172 172 if (sval_binop_overflows(lmax, op, rmax))
173 173 return 1;
174 174
175 175 res = sval_binop(lmax, op, rmax);
176 176 if (sval_cmp(res, sval_type_max(type)) > 0)
↓ open down ↓ |
176 lines elided |
↑ open up ↑ |
177 177 return 1;
178 178 return 0;
179 179 }
180 180
181 181 int can_integer_overflow_expr(struct expression *expr)
182 182 {
183 183 struct symbol *type;
184 184 struct smatch_state *state;
185 185 char *name;
186 186 struct symbol *sym;
187 - int ret;
187 + int ret = 1;
188 188
189 189 type = get_type(expr);
190 190 if (!type)
191 191 return 0;
192 192
193 193 if (!can_integer_overflow(type, expr))
194 194 return 0;
195 195
196 196 name = expr_to_known_chunk_sym(expr, &sym);
197 197 if (!name || !sym)
198 198 goto free;
199 199
200 200 state = get_state(my_id, name, sym);
201 201 if (state && state->data)
202 202 ret = 0;
203 203 free:
204 204 free_string(name);
205 205 return ret;
206 206 }
207 207
208 208 static int get_arg_nr(struct expression *call, struct expression *expr)
209 209 {
210 210 struct expression *arg;
211 211 int i;
212 212
213 213 i = -1;
214 214 FOR_EACH_PTR(call->args, arg) {
215 215 i++;
216 216 if (expr_equiv(arg, expr))
217 217 return i;
218 218 } END_FOR_EACH_PTR(arg);
219 219
220 220 return -1;
221 221 }
222 222
223 223 static void check_links(struct expression *call, struct expression *arg, int nr, struct sm_state *sm, void *_vsl)
224 224 {
225 225 struct var_sym_list *vsl = _vsl;
226 226 struct var_sym *vs;
227 227 struct smatch_state *state;
228 228 struct expression *expr;
229 229 int left = -1;
230 230 int right = -1;
231 231
232 232 FOR_EACH_PTR(vsl, vs) {
233 233 state = get_state(my_id, vs->var, vs->sym);
234 234 if (!state || !state->data)
235 235 continue;
236 236
237 237 expr = state->data;
238 238
239 239 if (expr_equiv(arg, expr->left)) {
240 240 left = nr;
241 241 right = get_arg_nr(call, expr->right);
242 242 } else if (expr_equiv(arg, expr->right)) {
243 243 left = get_arg_nr(call, expr->left);
244 244 right = nr;
245 245 }
246 246
247 247 if (left == -1 || right == -1)
248 248 continue;
249 249
250 250 left = -1;
251 251 right = -1;
252 252 } END_FOR_EACH_PTR(vs);
253 253 }
254 254
255 255 static void match_call_info(struct expression *call)
256 256 {
257 257 struct expression *arg;
258 258 struct sm_state *link;
259 259 struct stree *done = NULL;
260 260 int i;
261 261
262 262 i = -1;
263 263 FOR_EACH_PTR(call->args, arg) {
264 264 i++;
265 265
266 266 link = get_sm_state_expr(link_id, arg);
267 267 if (!link)
268 268 continue;
269 269
270 270 if (get_state_stree(done, my_id, link->state->name, NULL))
271 271 continue;
272 272 // set_state_stree(&done, my_id, link->state->name, NULL, &undefined);
273 273
274 274 check_links(call, arg, i, link, link->state->data);
275 275 } END_FOR_EACH_PTR(arg);
276 276
277 277 free_stree(&done);
278 278 }
279 279
280 280 void register_integer_overflow(int id)
281 281 {
282 282 my_id = id;
283 283 set_dynamic_states(my_id);
284 284 add_hook(&match_condition, CONDITION_HOOK);
285 285 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
286 286 }
287 287
288 288 void register_integer_overflow_links(int id)
289 289 {
290 290 link_id = id;
291 291 set_up_link_functions(my_id, link_id);
292 292 }
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX