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 int get_the_max(struct expression *expr, sval_t *sval) 39 { 40 struct range_list *rl; 41 42 if (get_hard_max(expr, sval)) 43 return 1; 44 if (!option_spammy) 45 return 0; 46 if (get_fuzzy_max(expr, sval)) 47 return 1; 48 if (get_user_rl(expr, &rl)) { 49 *sval = rl_max(rl); 50 return 1; 51 } 52 return 0; 53 } 54 55 static void array_check(struct expression *expr) 56 { 57 struct expression *array_expr; 58 int array_size; 59 struct expression *offset; 60 sval_t max; 61 62 expr = strip_expr(expr); 63 if (!is_array(expr)) 64 return; 65 66 array_expr = get_array_base(expr); 67 array_size = get_array_size(array_expr); 68 if (!array_size || array_size == 1) 69 return; 70 71 offset = get_array_offset(expr); 72 if (!get_the_max(offset, &max)) { 73 if (getting_address()) 74 return; 75 if (is_capped(offset)) 76 return; 77 set_state_expr(my_used_id, offset, alloc_state_num(array_size)); 78 } 79 } 80 81 static void match_condition(struct expression *expr) 82 { 83 int left; 84 sval_t sval; 85 struct state_list *slist; 86 struct sm_state *tmp; 87 int boundary; 88 89 if (!expr || expr->type != EXPR_COMPARE) 90 return; 91 if (get_macro_name(expr->pos)) 92 return; 93 if (get_implied_value(expr->left, &sval)) 94 left = 1; 95 else if (get_implied_value(expr->right, &sval)) 96 left = 0; 97 else 98 return; 99 100 if (left) 101 slist = get_possible_states_expr(my_used_id, expr->right); 102 else 103 slist = get_possible_states_expr(my_used_id, expr->left); 104 if (!slist) 105 return; 106 FOR_EACH_PTR(slist, tmp) { 107 if (tmp->state == &merged || tmp->state == &undefined) 108 continue; 109 boundary = PTR_INT(tmp->state->data); 110 boundary -= sval.value; 111 if (boundary < 1 && boundary > -1) { 112 char *name; 113 114 name = expr_to_var(left ? expr->right : expr->left); 115 sm_error("testing array offset '%s' after use.", name); 116 return; 117 } 118 } END_FOR_EACH_PTR(tmp); 119 } 120 121 void check_testing_index_after_use(int id) 122 { 123 my_used_id = id; 124 add_hook(&array_check, OP_HOOK); 125 add_hook(&match_condition, CONDITION_HOOK); 126 add_modification_hook(my_used_id, &delete); 127 } 128