1 /* 2 * Copyright (C) 2014 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 /* 19 * This file is sort of like check_dereferences_param.c. In theory the one 20 * difference should be that the param is NULL it should still be counted as a 21 * free. But for now I don't handle that case. 22 */ 23 24 #include "smatch.h" 25 #include "smatch_extra.h" 26 #include "smatch_slist.h" 27 28 static int my_id; 29 30 STATE(freed); 31 STATE(ignore); 32 STATE(param); 33 34 static void set_ignore(struct sm_state *sm, struct expression *mod_expr) 35 { 36 set_state(my_id, sm->name, sm->sym, &ignore); 37 } 38 39 static void match_function_def(struct symbol *sym) 40 { 41 struct symbol *arg; 42 int i; 43 44 i = -1; 45 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) { 46 i++; 47 if (!arg->ident) 48 continue; 49 set_state(my_id, arg->ident->name, arg, ¶m); 50 } END_FOR_EACH_PTR(arg); 51 } 52 53 static void freed_variable(struct expression *expr) 54 { 55 struct sm_state *sm; 56 57 expr = strip_expr(expr); 58 if (get_param_num(expr) < 0) 59 return; 60 61 sm = get_sm_state_expr(my_id, expr); 62 if (sm && slist_has_state(sm->possible, &ignore)) 63 return; 64 set_state_expr(my_id, expr, &freed); 65 } 66 67 static void match_free(const char *fn, struct expression *expr, void *param) 68 { 69 struct expression *arg; 70 71 arg = get_argument_from_call_expr(expr->args, PTR_INT(param)); 72 if (!arg) 73 return; 74 freed_variable(arg); 75 } 76 77 static void set_param_freed(struct expression *call, struct expression *arg, char *key, char *unused) 78 { 79 /* XXX FIXME: return_implies has been updated with more information */ 80 if (strcmp(key, "$") != 0) 81 return; 82 freed_variable(arg); 83 } 84 85 static void process_states(void) 86 { 87 struct sm_state *sm; 88 int param; 89 const char *param_name; 90 91 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { 92 if (sm->state != &freed) 93 continue; 94 param = get_param_num_from_sym(sm->sym); 95 if (param < 0) 96 continue; 97 param_name = get_param_name(sm); 98 if (!param_name) 99 continue; 100 sql_insert_return_implies(PARAM_FREED, param, param_name, "1"); 101 } END_FOR_EACH_SM(sm); 102 103 } 104 105 void check_frees_param(int id) 106 { 107 my_id = id; 108 109 if (option_project == PROJ_KERNEL) { 110 /* The kernel uses check_frees_param_strict.c */ 111 return; 112 } 113 114 add_hook(&match_function_def, FUNC_DEF_HOOK); 115 116 add_function_hook("free", &match_free, INT_PTR(0)); 117 118 select_return_implies_hook(PARAM_FREED, &set_param_freed); 119 add_modification_hook(my_id, &set_ignore); 120 121 all_return_states_hook(&process_states); 122 } 123