1 /* 2 * Copyright (C) 2009 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 /* 19 * This script is for finding functions like hcd_buffer_free() which free 20 * their arguments. After running it, add those functions to check_memory.c 21 */ 22 23 #include "smatch.h" 24 #include "smatch_slist.h" 25 26 static int my_id; 27 28 STATE(freed); 29 30 static struct symbol *this_func; 31 static struct tracker_list *freed_args = NULL; 32 33 static void match_function_def(struct symbol *sym) 34 { 35 this_func = sym; 36 } 37 38 static int is_arg(char *name, struct symbol *sym) 39 { 40 struct symbol *arg; 41 const char *arg_name; 42 43 FOR_EACH_PTR(this_func->ctype.base_type->arguments, arg) { 44 arg_name = (arg->ident?arg->ident->name:"-"); 45 if (sym == arg && !strcmp(name, arg_name)) 46 return 1; 47 } END_FOR_EACH_PTR(arg); 48 return 0; 49 } 50 51 static void match_kfree(const char *fn, struct expression *expr, void *info) 52 { 53 struct expression *tmp; 54 struct symbol *sym; 55 char *name; 56 57 tmp = get_argument_from_call_expr(expr->args, 0); 58 tmp = strip_expr(tmp); 59 name = expr_to_var_sym(tmp, &sym); 60 if (is_arg(name, sym)) { 61 set_state(my_id, name, sym, &freed); 62 } 63 free_string(name); 64 } 65 66 static int return_count = 0; 67 static void match_return(struct expression *ret_value) 68 { 69 struct stree *stree; 70 struct sm_state *tmp; 71 struct tracker *tracker; 72 73 if (__inline_fn) 74 return; 75 76 if (!return_count) { 77 stree = __get_cur_stree(); 78 FOR_EACH_MY_SM(my_id, stree, tmp) { 79 if (tmp->state == &freed) 80 add_tracker(&freed_args, my_id, tmp->name, 81 tmp->sym); 82 } END_FOR_EACH_SM(tmp); 83 } else { 84 FOR_EACH_PTR(freed_args, tracker) { 85 tmp = get_sm_state(my_id, tracker->name, tracker->sym); 86 if (tmp && tmp->state != &freed) 87 del_tracker(&freed_args, my_id, tracker->name, 88 tracker->sym); 89 } END_FOR_EACH_PTR(tracker); 90 } 91 } 92 93 static void print_arg(struct symbol *sym) 94 { 95 struct symbol *arg; 96 int i = 0; 97 98 FOR_EACH_PTR(this_func->ctype.base_type->arguments, arg) { 99 if (sym == arg) { 100 sm_info("free_arg %s %d", get_function(), i); 101 return; 102 } 103 i++; 104 } END_FOR_EACH_PTR(arg); 105 } 106 107 static void match_end_func(struct symbol *sym) 108 { 109 if (__inline_fn) 110 return; 111 if (is_reachable()) 112 match_return(NULL); 113 } 114 115 static void match_after_func(struct symbol *sym) 116 { 117 struct tracker *tracker; 118 119 if (__inline_fn) 120 return; 121 122 FOR_EACH_PTR(freed_args, tracker) { 123 print_arg(tracker->sym); 124 } END_FOR_EACH_PTR(tracker); 125 126 free_trackers_and_list(&freed_args); 127 return_count = 0; 128 } 129 130 void check_frees_argument(int id) 131 { 132 if (!option_info) 133 return; 134 135 my_id = id; 136 add_hook(&match_function_def, FUNC_DEF_HOOK); 137 if (option_project == PROJ_KERNEL) 138 add_function_hook("kfree", &match_kfree, NULL); 139 else 140 add_function_hook("free", &match_kfree, NULL); 141 add_hook(&match_return, RETURN_HOOK); 142 add_hook(&match_end_func, END_FUNC_HOOK); 143 add_hook(&match_after_func, AFTER_FUNC_HOOK); 144 } 145