Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_buf_comparison.c
+++ new/usr/src/tools/smatch/src/smatch_buf_comparison.c
1 1 /*
2 2 * Copyright (C) 2012 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 /*
19 19 * The point here is to store that a buffer has x bytes even if we don't know
20 20 * the value of x.
21 21 *
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
22 22 */
23 23
24 24 #include "smatch.h"
25 25 #include "smatch_extra.h"
26 26 #include "smatch_slist.h"
27 27
28 28 static int size_id;
29 29 static int link_id;
30 30
31 31 /*
32 - * We need this for code which does:
32 + * There is a bunch of code which does this:
33 33 *
34 34 * if (size)
35 35 * foo = malloc(size);
36 36 *
37 - * We want to record that the size of "foo" is "size" even after the merge.
37 + * So if "size" is non-zero then the size of "foo" is size. But really it's
38 + * also true if size is zero. It's just better to assume to not trample over
39 + * the data that we have by merging &undefined states.
38 40 *
39 41 */
40 42 static struct smatch_state *unmatched_state(struct sm_state *sm)
41 43 {
42 - struct expression *size_expr;
43 - sval_t sval;
44 -
45 - if (!sm->state->data)
46 - return &undefined;
47 - size_expr = sm->state->data;
48 - if (!get_implied_value(size_expr, &sval) || sval.value != 0)
49 - return &undefined;
50 44 return sm->state;
51 45 }
52 46
53 47 static struct smatch_state *merge_links(struct smatch_state *s1, struct smatch_state *s2)
54 48 {
55 49 struct expression *expr1, *expr2;
56 50
57 51 expr1 = s1->data;
58 52 expr2 = s2->data;
59 53
60 54 if (expr1 && expr2 && expr_equiv(expr1, expr2))
61 55 return s1;
62 56 return &merged;
63 57 }
64 58
65 59 static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
66 60 {
67 61 struct expression *expr;
68 62 struct sm_state *tmp;
69 63
70 64 expr = sm->state->data;
71 65 if (expr) {
72 66 set_state_expr(size_id, expr, &undefined);
73 67 set_state(link_id, sm->name, sm->sym, &undefined);
74 68 return;
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
75 69 }
76 70
77 71 FOR_EACH_PTR(sm->possible, tmp) {
78 72 expr = tmp->state->data;
79 73 if (expr)
80 74 set_state_expr(size_id, expr, &undefined);
81 75 } END_FOR_EACH_PTR(tmp);
82 76 set_state(link_id, sm->name, sm->sym, &undefined);
83 77 }
84 78
85 -static struct smatch_state *alloc_expr_state(struct expression *expr)
79 +static const char *limit_map[] = {
80 + "byte_count",
81 + "elem_count",
82 + "elem_last",
83 + "used_count",
84 + "used_last",
85 +};
86 +
87 +int state_to_limit(struct smatch_state *state)
86 88 {
89 + int i;
90 +
91 + if (!state || !state->data)
92 + return -1;
93 +
94 + for (i = 0; i < ARRAY_SIZE(limit_map); i++) {
95 + if (strncmp(state->name, limit_map[i], strlen(limit_map[i])) == 0)
96 + return i + BYTE_COUNT;
97 + }
98 +
99 + return -1;
100 +}
101 +
102 +const char *limit_type_str(unsigned int limit_type)
103 +{
104 + if (limit_type - BYTE_COUNT >= ARRAY_SIZE(limit_map)) {
105 + sm_msg("internal: wrong size type %u", limit_type);
106 + return "unknown";
107 + }
108 +
109 + return limit_map[limit_type - BYTE_COUNT];
110 +}
111 +
112 +static struct smatch_state *alloc_compare_size(int limit_type, struct expression *expr)
113 +{
87 114 struct smatch_state *state;
88 115 char *name;
116 + char buf[256];
89 117
90 118 state = __alloc_smatch_state(0);
91 119 expr = strip_expr(expr);
92 120 name = expr_to_str(expr);
93 - state->name = alloc_sname(name);
121 + snprintf(buf, sizeof(buf), "%s %s", limit_type_str(limit_type), name);
122 + state->name = alloc_sname(buf);
94 123 free_string(name);
95 124 state->data = expr;
96 125 return state;
97 126 }
98 127
99 128 static int bytes_per_element(struct expression *expr)
100 129 {
101 130 struct symbol *type;
102 131
103 132 type = get_type(expr);
104 133 if (!type)
105 134 return 0;
106 135
107 136 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
108 137 return 0;
109 138
110 139 type = get_base_type(type);
111 140 return type_bytes(type);
112 141 }
113 142
114 -static void db_save_type_links(struct expression *array, struct expression *size)
143 +static void db_save_type_links(struct expression *array, int type_limit, struct expression *size)
115 144 {
116 145 const char *array_name;
117 146
118 147 array_name = get_data_info_name(array);
119 148 if (!array_name)
120 149 array_name = "";
121 - sql_insert_data_info(size, ARRAY_LEN, array_name);
150 + sql_insert_data_info(size, type_limit, array_name);
122 151 }
123 152
124 153 static void match_alloc_helper(struct expression *pointer, struct expression *size)
125 154 {
126 155 struct expression *tmp;
127 156 struct sm_state *sm;
157 + int limit_type = ELEM_COUNT;
128 158 sval_t sval;
129 159 int cnt = 0;
130 160
131 161 pointer = strip_expr(pointer);
132 162 size = strip_expr(size);
133 163 if (!size || !pointer)
134 164 return;
135 165
136 166 while ((tmp = get_assigned_expr(size))) {
137 167 size = strip_expr(tmp);
138 168 if (cnt++ > 5)
139 169 break;
140 170 }
141 171
142 172 if (size->type == EXPR_BINOP && size->op == '*') {
143 173 struct expression *mult_left, *mult_right;
144 174
145 175 mult_left = strip_expr(size->left);
146 176 mult_right = strip_expr(size->right);
147 177
148 178 if (get_implied_value(mult_left, &sval) &&
149 179 sval.value == bytes_per_element(pointer))
150 180 size = mult_right;
151 181 else if (get_implied_value(mult_right, &sval) &&
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
152 182 sval.value == bytes_per_element(pointer))
153 183 size = mult_left;
154 184 else
155 185 return;
156 186 }
157 187
158 188 /* Only save links to variables, not fixed sizes */
159 189 if (get_value(size, &sval))
160 190 return;
161 191
162 - db_save_type_links(pointer, size);
163 - sm = set_state_expr(size_id, pointer, alloc_expr_state(size));
192 + if (size->type == EXPR_BINOP && size->op == '+' &&
193 + get_value(size->right, &sval) && sval.value == 1) {
194 + size = size->left;
195 + limit_type = ELEM_LAST;
196 + }
197 +
198 + db_save_type_links(pointer, limit_type, size);
199 + sm = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, size));
164 200 if (!sm)
165 201 return;
166 - set_state_expr(link_id, size, alloc_expr_state(pointer));
202 + set_state_expr(link_id, size, alloc_state_expr(pointer));
167 203 }
168 204
169 205 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
170 206 {
171 207 int size_arg = PTR_INT(_size_arg);
172 208 struct expression *pointer, *call, *arg;
173 209
174 210 pointer = strip_expr(expr->left);
175 211 call = strip_expr(expr->right);
176 212 arg = get_argument_from_call_expr(call->args, size_arg);
177 213 match_alloc_helper(pointer, arg);
178 214 }
179 215
180 216 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
181 217 {
182 218 int start_arg = PTR_INT(_start_arg);
183 219 struct expression *pointer, *call, *arg;
184 220 struct sm_state *tmp;
221 + int limit_type = ELEM_COUNT;
185 222 sval_t sval;
186 223
187 224 pointer = strip_expr(expr->left);
188 225 call = strip_expr(expr->right);
189 226 arg = get_argument_from_call_expr(call->args, start_arg);
190 227 if (get_implied_value(arg, &sval) &&
191 228 sval.value == bytes_per_element(pointer))
192 229 arg = get_argument_from_call_expr(call->args, start_arg + 1);
193 230
194 - db_save_type_links(pointer, arg);
195 - tmp = set_state_expr(size_id, pointer, alloc_expr_state(arg));
231 + if (arg->type == EXPR_BINOP && arg->op == '+' &&
232 + get_value(arg->right, &sval) && sval.value == 1) {
233 + arg = arg->left;
234 + limit_type = ELEM_LAST;
235 + }
236 +
237 + db_save_type_links(pointer, limit_type, arg);
238 + tmp = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, arg));
196 239 if (!tmp)
197 240 return;
198 - set_state_expr(link_id, arg, alloc_expr_state(pointer));
241 + set_state_expr(link_id, arg, alloc_state_expr(pointer));
199 242 }
200 243
201 -struct expression *get_size_variable(struct expression *buf)
244 +struct expression *get_size_variable(struct expression *buf, int *limit_type)
202 245 {
203 246 struct smatch_state *state;
204 247
205 248 state = get_state_expr(size_id, buf);
206 - if (state)
207 - return state->data;
208 - return NULL;
249 + if (!state)
250 + return NULL;
251 + *limit_type = state_to_limit(state);
252 + return state->data;
209 253 }
210 254
211 255 struct expression *get_array_variable(struct expression *size)
212 256 {
213 257 struct smatch_state *state;
214 258
215 259 state = get_state_expr(link_id, size);
216 260 if (state)
217 261 return state->data;
218 262 return NULL;
219 263 }
220 264
221 265 static void array_check(struct expression *expr)
222 266 {
223 267 struct expression *array;
224 268 struct expression *size;
225 269 struct expression *offset;
226 270 char *array_str, *offset_str;
271 + int limit_type;
227 272
228 273 expr = strip_expr(expr);
229 274 if (!is_array(expr))
230 275 return;
231 276
232 277 array = get_array_base(expr);
233 - size = get_size_variable(array);
278 + size = get_size_variable(array, &limit_type);
234 279 if (!size)
235 280 return;
281 + if (limit_type != ELEM_COUNT)
282 + return;
236 283 offset = get_array_offset(expr);
237 284 if (!possible_comparison(size, SPECIAL_EQUAL, offset))
238 285 return;
239 286
240 287 array_str = expr_to_str(array);
241 288 offset_str = expr_to_str(offset);
242 289 sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str);
243 290 free_string(array_str);
244 291 free_string(offset_str);
245 292 }
246 293
247 294 struct db_info {
248 295 char *name;
249 296 int ret;
250 297 };
251 298
252 299 static int db_limitter_callback(void *_info, int argc, char **argv, char **azColName)
253 300 {
254 301 struct db_info *info = _info;
255 302
256 303 /*
257 304 * If possible the limitters are tied to the struct they limit. If we
258 305 * aren't sure which struct they limit then we use them as limitters for
259 306 * everything.
260 307 */
261 308 if (!info->name || argv[0][0] == '\0' || strcmp(info->name, argv[0]) == 0)
262 309 info->ret = 1;
263 310 return 0;
264 311 }
265 312
266 313 static char *vsl_to_data_info_name(const char *name, struct var_sym_list *vsl)
267 314 {
268 315 struct var_sym *vs;
269 316 struct symbol *type;
270 317 static char buf[80];
271 318 const char *p;
272 319
273 320 if (ptr_list_size((struct ptr_list *)vsl) != 1)
274 321 return NULL;
275 322 vs = first_ptr_list((struct ptr_list *)vsl);
276 323
277 324 type = get_real_base_type(vs->sym);
278 325 if (!type || type->type != SYM_PTR)
279 326 goto top_level_name;
280 327 type = get_real_base_type(type);
281 328 if (!type || type->type != SYM_STRUCT)
282 329 goto top_level_name;
283 330 if (!type->ident)
284 331 goto top_level_name;
285 332
286 333 p = name;
287 334 while ((name = strstr(p, "->")))
288 335 p = name + 2;
289 336
290 337 snprintf(buf, sizeof(buf),"(struct %s)->%s", type->ident->name, p);
291 338 return alloc_sname(buf);
292 339
293 340 top_level_name:
294 341 if (!(vs->sym->ctype.modifiers & MOD_TOPLEVEL))
295 342 return NULL;
296 343 if (vs->sym->ctype.modifiers & MOD_STATIC)
297 344 snprintf(buf, sizeof(buf),"static %s", name);
298 345 else
299 346 snprintf(buf, sizeof(buf),"global %s", name);
300 347 return alloc_sname(buf);
301 348 }
302 349
303 350 int db_var_is_array_limit(struct expression *array, const char *name, struct var_sym_list *vsl)
304 351 {
305 352 char *size_name;
306 353 char *array_name = get_data_info_name(array);
307 354 struct db_info db_info = {.name = array_name,};
308 355
309 356 size_name = vsl_to_data_info_name(name, vsl);
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
310 357 if (!size_name)
311 358 return 0;
312 359
313 360 run_sql(db_limitter_callback, &db_info,
314 361 "select value from data_info where type = %d and data = '%s';",
315 362 ARRAY_LEN, size_name);
316 363
317 364 return db_info.ret;
318 365 }
319 366
320 -static int known_access_ok_comparison(struct expression *expr)
367 +int buf_comparison_index_ok(struct expression *expr)
321 368 {
322 369 struct expression *array;
323 370 struct expression *size;
324 371 struct expression *offset;
372 + int limit_type;
325 373 int comparison;
326 374
327 375 array = get_array_base(expr);
328 - size = get_size_variable(array);
376 + size = get_size_variable(array, &limit_type);
329 377 if (!size)
330 378 return 0;
331 379 offset = get_array_offset(expr);
332 - comparison = get_comparison(size, offset);
333 - if (comparison == '>' || comparison == SPECIAL_UNSIGNED_GT)
380 + comparison = get_comparison(offset, size);
381 + if (!comparison)
382 + return 0;
383 +
384 + if ((limit_type == ELEM_COUNT || limit_type == ELEM_LAST) &&
385 + (comparison == '<' || comparison == SPECIAL_UNSIGNED_LT))
334 386 return 1;
387 + if (limit_type == ELEM_LAST &&
388 + (comparison == SPECIAL_LTE ||
389 + comparison == SPECIAL_UNSIGNED_LTE ||
390 + comparison == SPECIAL_EQUAL))
391 + return 1;
335 392
336 393 return 0;
337 394 }
338 395
339 396 static int known_access_ok_numbers(struct expression *expr)
340 397 {
341 398 struct expression *array;
342 399 struct expression *offset;
343 400 sval_t max;
344 401 int size;
345 402
346 403 array = get_array_base(expr);
347 404 offset = get_array_offset(expr);
348 405
349 406 size = get_array_size(array);
350 407 if (size <= 0)
351 408 return 0;
352 409
353 410 get_absolute_max(offset, &max);
354 411 if (max.uvalue < size)
355 412 return 1;
356 413 return 0;
357 414 }
358 415
359 416 static void array_check_data_info(struct expression *expr)
360 417 {
361 418 struct expression *array;
362 419 struct expression *offset;
363 420 struct state_list *slist;
364 421 struct sm_state *sm;
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
365 422 struct compare_data *comp;
366 423 char *offset_name;
367 424 const char *equal_name = NULL;
368 425
369 426 expr = strip_expr(expr);
370 427 if (!is_array(expr))
371 428 return;
372 429
373 430 if (known_access_ok_numbers(expr))
374 431 return;
375 - if (known_access_ok_comparison(expr))
432 + if (buf_comparison_index_ok(expr))
376 433 return;
377 434
378 435 array = get_array_base(expr);
379 436 offset = get_array_offset(expr);
380 437 offset_name = expr_to_var(offset);
381 438 if (!offset_name)
382 439 return;
383 440 slist = get_all_possible_equal_comparisons(offset);
384 441 if (!slist)
385 442 goto free;
386 443
387 444 FOR_EACH_PTR(slist, sm) {
388 445 comp = sm->state->data;
389 446 if (strcmp(comp->left_var, offset_name) == 0) {
390 447 if (db_var_is_array_limit(array, comp->right_var, comp->right_vsl)) {
391 448 equal_name = comp->right_var;
392 449 break;
393 450 }
394 451 } else if (strcmp(comp->right_var, offset_name) == 0) {
395 452 if (db_var_is_array_limit(array, comp->left_var, comp->left_vsl)) {
396 453 equal_name = comp->left_var;
397 454 break;
398 455 }
399 456 }
400 457 } END_FOR_EACH_PTR(sm);
401 458
402 459 if (equal_name) {
403 460 char *array_name = expr_to_str(array);
404 461
405 462 sm_warning("potential off by one '%s[]' limit '%s'", array_name, equal_name);
406 463 free_string(array_name);
407 464 }
408 465
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
409 466 free:
410 467 free_slist(&slist);
411 468 free_string(offset_name);
412 469 }
413 470
414 471 static void add_allocation_function(const char *func, void *call_back, int param)
415 472 {
416 473 add_function_assign_hook(func, call_back, INT_PTR(param));
417 474 }
418 475
419 -static char *buf_size_param_comparison(struct expression *array, struct expression_list *args)
476 +static int is_sizeof(struct expression *expr)
420 477 {
421 - struct expression *arg;
478 + const char *name;
479 +
480 + if (expr->type == EXPR_SIZEOF)
481 + return 1;
482 + name = pos_ident(expr->pos);
483 + if (name && strcmp(name, "sizeof") == 0)
484 + return 1;
485 + return 0;
486 +}
487 +
488 +static int match_size_binop(struct expression *size, struct expression *expr, int *limit_type)
489 +{
490 + int orig_type = *limit_type;
491 + struct expression *left;
492 + sval_t sval;
493 +
494 + left = expr->left;
495 + if (!expr_equiv(size, left))
496 + return 0;
497 +
498 + if (expr->op == '-' &&
499 + get_value(expr->right, &sval) &&
500 + sval.value == 1 &&
501 + orig_type == ELEM_COUNT) {
502 + *limit_type = ELEM_LAST;
503 + return 1;
504 + }
505 +
506 + if (expr->op == '+' &&
507 + get_value(expr->right, &sval) &&
508 + sval.value == 1 &&
509 + orig_type == ELEM_LAST) {
510 + *limit_type = ELEM_COUNT;
511 + return 1;
512 + }
513 +
514 + if (expr->op == '*' &&
515 + is_sizeof(expr->right) &&
516 + orig_type == ELEM_COUNT) {
517 + *limit_type = BYTE_COUNT;
518 + return 1;
519 + }
520 +
521 + if (expr->op == '/' &&
522 + is_sizeof(expr->right) &&
523 + orig_type == BYTE_COUNT) {
524 + *limit_type = ELEM_COUNT;
525 + return 1;
526 + }
527 +
528 + return 0;
529 +}
530 +
531 +static char *buf_size_param_comparison(struct expression *array, struct expression_list *args, int *limit_type)
532 +{
533 + struct expression *tmp, *arg;
422 534 struct expression *size;
423 535 static char buf[32];
424 536 int i;
425 537
426 - size = get_size_variable(array);
538 + size = get_size_variable(array, limit_type);
427 539 if (!size)
428 540 return NULL;
429 541
542 + if (*limit_type == USED_LAST)
543 + *limit_type = ELEM_LAST;
544 + if (*limit_type == USED_COUNT)
545 + *limit_type = ELEM_COUNT;
546 +
430 547 i = -1;
431 - FOR_EACH_PTR(args, arg) {
548 + FOR_EACH_PTR(args, tmp) {
432 549 i++;
550 + arg = tmp;
433 551 if (arg == array)
434 552 continue;
435 - if (!expr_equiv(arg, size))
436 - continue;
437 - snprintf(buf, sizeof(buf), "==$%d", i);
438 - return buf;
439 - } END_FOR_EACH_PTR(arg);
553 + if (expr_equiv(arg, size) ||
554 + (arg->type == EXPR_BINOP &&
555 + match_size_binop(size, arg, limit_type))) {
556 + snprintf(buf, sizeof(buf), "==$%d", i);
557 + return buf;
558 + }
559 + } END_FOR_EACH_PTR(tmp);
440 560
441 561 return NULL;
442 562 }
443 563
444 564 static void match_call(struct expression *call)
445 565 {
446 566 struct expression *arg;
447 567 char *compare;
448 568 int param;
569 + char buf[5];
570 + int limit_type;
449 571
450 572 param = -1;
451 573 FOR_EACH_PTR(call->args, arg) {
452 574 param++;
453 575 if (!is_pointer(arg))
454 576 continue;
455 - compare = buf_size_param_comparison(arg, call->args);
577 + compare = buf_size_param_comparison(arg, call->args, &limit_type);
456 578 if (!compare)
457 579 continue;
458 - sql_insert_caller_info(call, ARRAY_LEN, param, "$", compare);
580 + snprintf(buf, sizeof(buf), "%d", limit_type);
581 + sql_insert_caller_info(call, limit_type, param, compare, buf);
459 582 } END_FOR_EACH_PTR(arg);
460 583 }
461 584
462 585 static int get_param(int param, char **name, struct symbol **sym)
463 586 {
464 587 struct symbol *arg;
465 588 int i;
466 589
467 590 i = 0;
468 591 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
469 592 /*
470 593 * this is a temporary hack to work around a bug (I think in sparse?)
471 594 * 2.6.37-rc1:fs/reiserfs/journal.o
472 595 * If there is a function definition without parameter name found
473 596 * after a function implementation then it causes a crash.
474 597 * int foo() {}
475 598 * int bar(char *);
476 599 */
477 600 if (arg->ident->name < (char *)100)
478 601 continue;
479 602 if (i == param) {
480 603 *name = arg->ident->name;
481 604 *sym = arg;
482 605 return TRUE;
483 606 }
484 607 i++;
485 608 } END_FOR_EACH_PTR(arg);
486 609
487 610 return FALSE;
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
488 611 }
489 612
490 613 static void set_param_compare(const char *array_name, struct symbol *array_sym, char *key, char *value)
491 614 {
492 615 struct expression *array_expr;
493 616 struct expression *size_expr;
494 617 struct symbol *size_sym;
495 618 char *size_name;
496 619 long param;
497 620 struct sm_state *tmp;
621 + int limit_type;
498 622
499 - if (strncmp(value, "==$", 3) != 0)
623 + if (strncmp(key, "==$", 3) != 0)
500 624 return;
501 - param = strtol(value + 3, NULL, 10);
625 + param = strtol(key + 3, NULL, 10);
502 626 if (!get_param(param, &size_name, &size_sym))
503 627 return;
504 628 array_expr = symbol_expression(array_sym);
505 629 size_expr = symbol_expression(size_sym);
630 + limit_type = strtol(value, NULL, 10);
506 631
507 - tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
632 + tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
508 633 if (!tmp)
509 634 return;
510 - set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
635 + set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
511 636 }
512 637
513 -static void set_arraysize_arg(const char *array_name, struct symbol *array_sym, char *key, char *value)
638 +static void set_implied(struct expression *call, struct expression *array_expr, char *key, char *value)
514 639 {
515 - struct expression *array_expr;
516 640 struct expression *size_expr;
517 641 struct symbol *size_sym;
518 642 char *size_name;
519 643 long param;
520 644 struct sm_state *tmp;
645 + int limit_type;
521 646
522 - param = strtol(key, NULL, 10);
647 + if (strncmp(key, "==$", 3) != 0)
648 + return;
649 + param = strtol(key + 3, NULL, 10);
523 650 if (!get_param(param, &size_name, &size_sym))
524 651 return;
525 - array_expr = symbol_expression(array_sym);
526 652 size_expr = symbol_expression(size_sym);
527 653
528 - tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
654 + limit_type = strtol(value, NULL, 10);
655 + tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
529 656 if (!tmp)
530 657 return;
531 - set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
658 + set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
532 659 }
533 660
534 661 static void munge_start_states(struct statement *stmt)
535 662 {
536 663 struct state_list *slist = NULL;
537 664 struct sm_state *sm;
538 665 struct sm_state *poss;
539 666
540 667 FOR_EACH_MY_SM(size_id, __get_cur_stree(), sm) {
541 668 if (sm->state != &merged)
542 669 continue;
543 670 /*
544 671 * screw it. let's just assume that if one caller passes the
545 672 * size then they all do.
546 673 */
547 674 FOR_EACH_PTR(sm->possible, poss) {
548 675 if (poss->state != &merged &&
549 676 poss->state != &undefined) {
550 677 add_ptr_list(&slist, poss);
551 678 break;
552 679 }
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
553 680 } END_FOR_EACH_PTR(poss);
554 681 } END_FOR_EACH_SM(sm);
555 682
556 683 FOR_EACH_PTR(slist, sm) {
557 684 set_state(size_id, sm->name, sm->sym, sm->state);
558 685 } END_FOR_EACH_PTR(sm);
559 686
560 687 free_slist(&slist);
561 688 }
562 689
690 +static void set_used(struct expression *expr)
691 +{
692 + struct expression *parent;
693 + struct expression *array;
694 + struct expression *offset;
695 + struct sm_state *tmp;
696 + int limit_type;
697 +
698 + if (expr->op != SPECIAL_INCREMENT)
699 + return;
700 +
701 + limit_type = USED_LAST;
702 + if (expr->type == EXPR_POSTOP)
703 + limit_type = USED_COUNT;
704 +
705 + parent = expr_get_parent_expr(expr);
706 + if (!parent || parent->type != EXPR_BINOP)
707 + return;
708 + parent = expr_get_parent_expr(parent);
709 + if (!parent || !is_array(parent))
710 + return;
711 +
712 + array = get_array_base(parent);
713 + offset = get_array_offset(parent);
714 + if (offset != expr)
715 + return;
716 +
717 + tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, offset->unop));
718 + if (!tmp)
719 + return;
720 + set_state_expr(link_id, offset->unop, alloc_state_expr(array));
721 +}
722 +
723 +static int match_assign_array(struct expression *expr)
724 +{
725 + // FIXME: implement
726 + return 0;
727 +}
728 +
729 +static int match_assign_size(struct expression *expr)
730 +{
731 + struct expression *right, *size, *array;
732 + struct smatch_state *state;
733 + struct sm_state *tmp;
734 + int limit_type;
735 +
736 + right = expr->right;
737 + size = right;
738 + if (size->type == EXPR_BINOP)
739 + size = size->left;
740 +
741 + array = get_array_variable(size);
742 + if (!array)
743 + return 0;
744 + state = get_state_expr(size_id, array);
745 + if (!state || !state->data)
746 + return 0;
747 +
748 + limit_type = state_to_limit(state);
749 + if (limit_type < 0)
750 + return 0;
751 +
752 + if (right->type == EXPR_BINOP && !match_size_binop(size, right, &limit_type))
753 + return 0;
754 +
755 + tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, expr->left));
756 + if (!tmp)
757 + return 0;
758 + set_state_expr(link_id, expr->left, alloc_state_expr(array));
759 + return 1;
760 +}
761 +
762 +static void match_assign(struct expression *expr)
763 +{
764 + if (expr->op != '=')
765 + return;
766 +
767 + if (match_assign_array(expr))
768 + return;
769 + match_assign_size(expr);
770 +}
771 +
772 +static void match_copy(const char *fn, struct expression *expr, void *unused)
773 +{
774 + struct expression *src, *size;
775 + int src_param, size_param;
776 +
777 + src = get_argument_from_call_expr(expr->args, 1);
778 + size = get_argument_from_call_expr(expr->args, 2);
779 + src = strip_expr(src);
780 + size = strip_expr(size);
781 + if (!src || !size)
782 + return;
783 + if (src->type != EXPR_SYMBOL || size->type != EXPR_SYMBOL)
784 + return;
785 +
786 + src_param = get_param_num_from_sym(src->symbol);
787 + size_param = get_param_num_from_sym(size->symbol);
788 + if (src_param < 0 || size_param < 0)
789 + return;
790 +
791 + sql_insert_cache(call_implies, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'",
792 + get_base_file(), get_function(), fn_static(),
793 + BYTE_COUNT, src_param, size_param, BYTE_COUNT);
794 +}
795 +
563 796 void register_buf_comparison(int id)
564 797 {
798 + int i;
799 +
565 800 size_id = id;
566 801
802 + set_dynamic_states(size_id);
803 +
567 804 add_unmatched_state_hook(size_id, &unmatched_state);
568 805
569 806 add_allocation_function("malloc", &match_alloc, 0);
570 807 add_allocation_function("memdup", &match_alloc, 1);
571 808 add_allocation_function("realloc", &match_alloc, 1);
572 809 if (option_project == PROJ_KERNEL) {
573 810 add_allocation_function("kmalloc", &match_alloc, 0);
574 811 add_allocation_function("kzalloc", &match_alloc, 0);
575 812 add_allocation_function("vmalloc", &match_alloc, 0);
576 813 add_allocation_function("__vmalloc", &match_alloc, 0);
577 814 add_allocation_function("sock_kmalloc", &match_alloc, 1);
578 815 add_allocation_function("kmemdup", &match_alloc, 1);
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
579 816 add_allocation_function("kmemdup_user", &match_alloc, 1);
580 817 add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
581 818 add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
582 819 add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
583 820 add_allocation_function("devm_kmalloc", &match_alloc, 1);
584 821 add_allocation_function("devm_kzalloc", &match_alloc, 1);
585 822 add_allocation_function("kcalloc", &match_calloc, 0);
586 823 add_allocation_function("devm_kcalloc", &match_calloc, 1);
587 824 add_allocation_function("kmalloc_array", &match_calloc, 0);
588 825 add_allocation_function("krealloc", &match_alloc, 1);
826 +
827 + add_function_hook("copy_from_user", &match_copy, NULL);
828 + add_function_hook("__copy_from_user", &match_copy, NULL);
589 829 }
590 830
591 831 add_hook(&array_check, OP_HOOK);
592 832 add_hook(&array_check_data_info, OP_HOOK);
833 + add_hook(&set_used, OP_HOOK);
593 834
594 835 add_hook(&match_call, FUNCTION_CALL_HOOK);
595 - select_caller_info_hook(set_param_compare, ARRAY_LEN);
596 - select_caller_info_hook(set_arraysize_arg, ARRAYSIZE_ARG);
597 836 add_hook(&munge_start_states, AFTER_DEF_HOOK);
837 +
838 + add_hook(&match_assign, ASSIGNMENT_HOOK);
839 +
840 + for (i = BYTE_COUNT; i <= USED_COUNT; i++) {
841 + select_call_implies_hook(i, &set_implied);
842 + select_caller_info_hook(set_param_compare, i);
843 + select_return_implies_hook(i, &set_implied);
844 + }
598 845 }
599 846
600 847 void register_buf_comparison_links(int id)
601 848 {
602 849 link_id = id;
850 + set_dynamic_states(link_id);
603 851 add_merge_hook(link_id, &merge_links);
604 852 add_modification_hook(link_id, &match_link_modify);
605 853 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX