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 
match_function_def(struct symbol * sym)33 static void match_function_def(struct symbol *sym)
34 {
35 	this_func = sym;
36 }
37 
parent_is_arg(struct symbol * sym)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 
match_put(const char * fn,struct expression * expr,void * info)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;
match_return(struct expression * ret_value)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 
print_arg(struct symbol * sym)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 
match_end_func(struct symbol * sym)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 
check_puts_argument(int id)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 }
134