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(putted);
  29 
  30 static struct symbol *this_func;
  31 static struct tracker_list *putted_args = NULL;
  32 
  33 static void match_function_def(struct symbol *sym)
  34 {
  35         this_func = sym;
  36 }
  37 
  38 static int parent_is_arg(struct symbol *sym)
  39 {
  40         struct symbol *arg;
  41 
  42         FOR_EACH_PTR(this_func->ctype.base_type->arguments, arg) {
  43                 if (sym == arg)
  44                         return 1;
  45         } END_FOR_EACH_PTR(arg);
  46         return 0;
  47 }
  48 
  49 static void match_put(const char *fn, struct expression *expr, void *info)
  50 {
  51         struct expression *tmp;
  52         struct symbol *sym;
  53         char *name;
  54 
  55         tmp = get_argument_from_call_expr(expr->args, 0);
  56         tmp = strip_expr(tmp);
  57         name = expr_to_var_sym(tmp, &sym);
  58         free_string(name);
  59         if (parent_is_arg(sym) && sym->ident)
  60                 set_state(my_id, sym->ident->name, sym, &putted);
  61 }
  62 
  63 static int return_count = 0;
  64 static void match_return(struct expression *ret_value)
  65 {
  66         struct stree *stree;
  67         struct sm_state *tmp;
  68         struct tracker *tracker;
  69 
  70         if (__inline_fn)
  71                 return;
  72 
  73         if (!return_count) {
  74                 stree = __get_cur_stree();
  75                 FOR_EACH_MY_SM(my_id, stree, tmp) {
  76                         if (tmp->state == &putted)
  77                                 add_tracker(&putted_args, my_id, tmp->name, 
  78                                             tmp->sym);
  79                 } END_FOR_EACH_SM(tmp);
  80         } else {
  81                 FOR_EACH_PTR(putted_args, tracker) {
  82                         tmp = get_sm_state(my_id, tracker->name, tracker->sym);
  83                         if (tmp && tmp->state != &putted)
  84                                 del_tracker(&putted_args, my_id, tracker->name, 
  85                                             tracker->sym);
  86                 } END_FOR_EACH_PTR(tracker);
  87                 
  88         }
  89 }
  90 
  91 static void print_arg(struct symbol *sym)
  92 {
  93         struct symbol *arg;
  94         int i = 0;
  95 
  96         FOR_EACH_PTR(this_func->ctype.base_type->arguments, arg) {
  97                 if (sym == arg) {
  98                         sm_info("puts_arg %s %d", get_function(), i);
  99                         return;
 100                 }
 101                 i++;
 102         } END_FOR_EACH_PTR(arg);
 103 }
 104 
 105 static void match_end_func(struct symbol *sym)
 106 {
 107         struct tracker *tracker;
 108 
 109         if (__inline_fn)
 110                 return;
 111         if (is_reachable())
 112                 match_return(NULL);
 113 
 114         FOR_EACH_PTR(putted_args, tracker) {
 115                 print_arg(tracker->sym);
 116         } END_FOR_EACH_PTR(tracker);
 117 
 118         free_trackers_and_list(&putted_args);
 119         return_count = 0;
 120 }
 121 
 122 void check_puts_argument(int id)
 123 {
 124         if (!option_info || option_project != PROJ_KERNEL)
 125                 return;
 126 
 127         my_id = id;
 128         add_hook(&match_function_def, FUNC_DEF_HOOK);
 129         add_function_hook("kobject_put", &match_put, NULL);
 130         add_function_hook("kref_put", &match_put, NULL);
 131         add_hook(&match_return, RETURN_HOOK);
 132         add_hook(&match_end_func, END_FUNC_HOOK);
 133 }