1 /* 2 * Copyright (C) 2012 Oracle. 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 "smatch.h" 19 20 static int my_id; 21 22 STATE(size_in_bytes); 23 24 static void set_undefined(struct sm_state *sm, struct expression *mod_expr) 25 { 26 if (sm->state == &size_in_bytes) 27 set_state(my_id, sm->name, sm->sym, &undefined); 28 } 29 30 static int is_sizeof(struct expression *expr) 31 { 32 return (expr->type == EXPR_SIZEOF); 33 } 34 35 static int is_macro(struct expression *expr, const char *macro_name) 36 { 37 char *name; 38 struct expression *outside_expr; 39 40 /* check that we aren't inside the macro itself */ 41 outside_expr = last_ptr_list((struct ptr_list *)big_expression_stack); 42 if (outside_expr && positions_eq(expr->pos, outside_expr->pos)) 43 return 0; 44 45 name = get_macro_name(expr->pos); 46 if (name && strcmp(name, macro_name) == 0) 47 return 1; 48 return 0; 49 } 50 51 static int is_size_in_bytes(struct expression *expr) 52 { 53 if (is_sizeof(expr)) 54 return 1; 55 56 if (is_macro(expr, "offsetof")) 57 return 1; 58 if (is_macro(expr, "PAGE_SIZE")) 59 return 1; 60 61 if (get_state_expr(my_id, expr) == &size_in_bytes) 62 return 1; 63 64 return 0; 65 } 66 67 static void match_binop(struct expression *expr) 68 { 69 struct symbol *type; 70 char *name; 71 int size; 72 73 if (expr->op != '+') 74 return; 75 type = get_pointer_type(expr->left); 76 if (!type) 77 return; 78 if (type_bits(type) <= 8) /* ignore void, bool and char pointers*/ 79 return; 80 if (!is_size_in_bytes(expr->right)) 81 return; 82 83 /* if we know it's within bounds then don't complain */ 84 size = get_array_size(expr->left); 85 if (size) { 86 sval_t max; 87 88 get_absolute_max(expr->right, &max); 89 if (max.uvalue < size) 90 return; 91 } 92 93 name = expr_to_str(expr->left); 94 sm_warning("potential pointer math issue ('%s' is a %d bit pointer)", 95 name, type_bits(type)); 96 free_string(name); 97 } 98 99 static void match_assign(struct expression *expr) 100 { 101 if (expr->op != '=') 102 return; 103 104 if (!is_size_in_bytes(expr->right)) 105 return; 106 set_state_expr(my_id, expr->left, &size_in_bytes); 107 } 108 109 static void check_assign(struct expression *expr) 110 { 111 struct symbol *type; 112 char *name; 113 114 if (expr->op != SPECIAL_ADD_ASSIGN && expr->op != SPECIAL_SUB_ASSIGN) 115 return; 116 117 type = get_pointer_type(expr->left); 118 if (!type) 119 return; 120 if (type_bits(type) == 8 || type_bits(type) == -1) 121 return; 122 if (!is_size_in_bytes(expr->right)) 123 return; 124 name = expr_to_var(expr->left); 125 sm_warning("potential pointer math issue ('%s' is a %d bit pointer)", 126 name, type_bits(type)); 127 free_string(name); 128 } 129 130 void check_pointer_math(int id) 131 { 132 my_id = id; 133 add_hook(&match_binop, BINOP_HOOK); 134 add_hook(&match_assign, ASSIGNMENT_HOOK); 135 add_hook(&check_assign, ASSIGNMENT_HOOK); 136 add_modification_hook(my_id, &set_undefined); 137 } 138