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 static void check_pointer(struct expression *expr, char *ptr_name) 23 { 24 char *name; 25 sval_t sval; 26 27 if (!expr || expr->type != EXPR_SIZEOF) 28 return; 29 30 get_value(expr, &sval); 31 32 expr = strip_expr(expr->cast_expression); 33 name = expr_to_str(expr); 34 if (!name) 35 return; 36 37 if (strcmp(ptr_name, name) == 0) 38 sm_warning("was 'sizeof(*%s)' intended?", ptr_name); 39 free_string(name); 40 } 41 42 static void match_call_assignment(struct expression *expr) 43 { 44 struct expression *call = strip_expr(expr->right); 45 struct expression *arg; 46 char *ptr_name; 47 48 if (!is_pointer(expr->left)) 49 return; 50 51 ptr_name = expr_to_str(expr->left); 52 if (!ptr_name) 53 return; 54 55 FOR_EACH_PTR(call->args, arg) { 56 check_pointer(arg, ptr_name); 57 } END_FOR_EACH_PTR(arg); 58 59 free_string(ptr_name); 60 } 61 62 static void check_passes_pointer(char *name, struct expression *call) 63 { 64 struct expression *arg; 65 char *ptr_name; 66 67 FOR_EACH_PTR(call->args, arg) { 68 ptr_name = expr_to_var(arg); 69 if (!ptr_name) 70 continue; 71 if (strcmp(name, ptr_name) == 0) 72 sm_warning("was 'sizeof(*%s)' intended?", name); 73 free_string(ptr_name); 74 } END_FOR_EACH_PTR(arg); 75 } 76 77 static void match_check_params(struct expression *call) 78 { 79 struct expression *arg; 80 struct expression *obj; 81 char *name; 82 83 FOR_EACH_PTR(call->args, arg) { 84 if (arg->type != EXPR_SIZEOF) 85 continue; 86 obj = strip_expr(arg->cast_expression); 87 if (!is_pointer(obj)) 88 continue; 89 name = expr_to_var(obj); 90 if (!name) 91 continue; 92 check_passes_pointer(name, call); 93 free_string(name); 94 } END_FOR_EACH_PTR(arg); 95 } 96 97 static struct string_list *macro_takes_sizeof_argument; 98 static void check_sizeof_number(struct expression *expr) 99 { 100 char *macro, *tmp; 101 102 if (expr->type != EXPR_VALUE) 103 return; 104 macro = get_macro_name(expr->pos); 105 FOR_EACH_PTR(macro_takes_sizeof_argument, tmp) { 106 if (macro && strcmp(tmp, macro) == 0) 107 return; 108 } END_FOR_EACH_PTR(tmp); 109 110 sm_warning("sizeof(NUMBER)?"); 111 } 112 113 static void match_sizeof(struct expression *expr) 114 { 115 check_sizeof_number(expr); 116 if (expr->type == EXPR_PREOP && expr->op == '&') 117 sm_warning("sizeof(&pointer)?"); 118 if (expr->type == EXPR_SIZEOF) 119 sm_warning("sizeof(sizeof())?"); 120 /* the ilog2() macro is a valid place to check the size of a binop */ 121 if (expr->type == EXPR_BINOP && !get_macro_name(expr->pos)) 122 sm_warning("taking sizeof binop"); 123 } 124 125 static void register_macro_takes_sizeof_argument(void) 126 { 127 struct token *token; 128 char *macro; 129 char name[256]; 130 131 snprintf(name, 256, "%s.macro_takes_sizeof_argument", option_project_str); 132 133 token = get_tokens_file(name); 134 if (!token) 135 return; 136 if (token_type(token) != TOKEN_STREAMBEGIN) 137 return; 138 token = token->next; 139 while (token_type(token) != TOKEN_STREAMEND) { 140 if (token_type(token) != TOKEN_IDENT) 141 return; 142 macro = alloc_string(show_ident(token->ident)); 143 add_ptr_list(¯o_takes_sizeof_argument, macro); 144 token = token->next; 145 } 146 clear_token_alloc(); 147 } 148 149 void check_sizeof(int id) 150 { 151 my_id = id; 152 153 register_macro_takes_sizeof_argument(); 154 add_hook(&match_call_assignment, CALL_ASSIGNMENT_HOOK); 155 add_hook(&match_check_params, FUNCTION_CALL_HOOK); 156 add_hook(&match_sizeof, SIZEOF_HOOK); 157 } 158