1 /* 2 * Copyright (C) 2010 Dan Carpenter. 3 * 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. 8 * 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. 13 * 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 16 */ 17 18 #include <stdlib.h> 19 #include "parse.h" 20 #include "smatch.h" 21 #include "smatch_slist.h" 22 #include "smatch_extra.h" 23 24 /* 25 * This check has two smatch IDs. 26 * my_used_id - keeps a record of array offsets that have been used. 27 * If the code checks that they are within bounds later on, 28 * we complain about using an array offset before checking 29 * that it is within bounds. 30 */ 31 static int my_used_id; 32 33 static void delete(struct sm_state *sm, struct expression *mod_expr) 34 { 35 set_state(my_used_id, sm->name, sm->sym, &undefined); 36 } 37 38 static void array_check(struct expression *expr) 39 { 40 struct expression *array_expr; 41 int array_size; 42 struct expression *offset; 43 struct range_list *rl; 44 45 expr = strip_expr(expr); 46 if (!is_array(expr)) 47 return; 48 49 array_expr = get_array_base(expr); 50 array_size = get_array_size(array_expr); 51 if (!array_size || array_size == 1) 52 return; 53 54 offset = get_array_offset(expr); 55 get_absolute_rl(offset, &rl); 56 if (rl_max(rl).uvalue < array_size) 57 return; 58 if (buf_comparison_index_ok(expr)) 59 return; 60 61 if (getting_address(expr)) 62 return; 63 if (is_capped(offset)) 64 return; 65 set_state_expr(my_used_id, offset, alloc_state_num(array_size)); 66 } 67 68 static void match_condition(struct expression *expr) 69 { 70 int left; 71 sval_t sval; 72 struct state_list *slist; 73 struct sm_state *tmp; 74 int boundary; 75 76 if (!expr || expr->type != EXPR_COMPARE) 77 return; 78 if (get_macro_name(expr->pos)) 79 return; 80 if (get_implied_value(expr->left, &sval)) 81 left = 1; 82 else if (get_implied_value(expr->right, &sval)) 83 left = 0; 84 else 85 return; 86 87 if (left) 88 slist = get_possible_states_expr(my_used_id, expr->right); 89 else 90 slist = get_possible_states_expr(my_used_id, expr->left); 91 if (!slist) 92 return; 93 FOR_EACH_PTR(slist, tmp) { 94 if (tmp->state == &merged || tmp->state == &undefined) 95 continue; 96 boundary = PTR_INT(tmp->state->data); 97 boundary -= sval.value; 98 if (boundary < 1 && boundary > -1) { 99 char *name; 100 101 name = expr_to_var(left ? expr->right : expr->left); 102 sm_error("testing array offset '%s' after use.", name); 103 return; 104 } 105 } END_FOR_EACH_PTR(tmp); 106 } 107 108 void check_testing_index_after_use(int id) 109 { 110 my_used_id = id; 111 set_dynamic_states(my_used_id); 112 add_hook(&array_check, OP_HOOK); 113 add_hook(&match_condition, CONDITION_HOOK); 114 add_modification_hook(my_used_id, &delete); 115 } 116