Fix string memory leaks.
[smatch.git] / check_memory.c
blob1e0ae7957beb1bedcd535317e8236da0d850b939
1 /*
2 * sparse/check_memory.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "parse.h"
11 #include "smatch.h"
12 #include "smatch_slist.h"
14 static int my_id;
16 STATE(allocated);
17 STATE(assigned);
18 STATE(isfree);
19 STATE(returned);
20 STATE(unfree);
22 static const char *allocation_funcs[] = {
23 "malloc",
24 "kmalloc",
25 NULL,
28 static int is_allocation(struct expression *expr)
30 char *fn_name;
31 int i;
33 if (expr->type != EXPR_CALL)
34 return 0;
36 if (!(fn_name = get_variable_from_expr(expr->fn, NULL)))
37 return 0;
39 for (i = 0; allocation_funcs[i]; i++) {
40 if (!strcmp(fn_name, allocation_funcs[i])) {
41 free_string(fn_name);
42 return 1;
45 free_string(fn_name);
46 return 0;
49 static int is_freed(const char *name, struct symbol *sym)
51 struct state_list *slist;
53 slist = get_possible_states(name, my_id, sym);
54 if (slist_has_state(slist, &isfree)) {
55 return 1;
57 return 0;
60 static void match_assign(struct expression *expr)
62 struct expression *left, *right;
63 char *left_name, *right_name;
64 struct symbol *left_sym, *right_sym;
65 struct smatch_state *state;
67 left = strip_expr(expr->left);
68 left_name = get_variable_from_expr(left, &left_sym);
69 if (!left_name)
70 return;
71 if (!left_sym) {
72 free_string(left_name);
73 return;
76 right = strip_expr(expr->right);
77 if (is_allocation(right) && !(left_sym->ctype.modifiers &
78 (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))) {
79 set_state(left_name, my_id, left_sym, &allocated);
80 free_string(left_name);
81 return;
84 right_name = get_variable_from_expr(right, &right_sym);
85 if (right_name && (state = get_state(right_name, my_id, right_sym))) {
86 if (state == &isfree)
87 smatch_msg("assigning freed pointer");
88 set_state(right_name, my_id, right_sym, &assigned);
90 free_string(right_name);
92 if (is_freed(left_name, left_sym)) {
93 set_state(left_name, my_id, left_sym, &unfree);
95 free_string(left_name);
98 static int is_null(char *name, struct symbol *sym)
100 struct smatch_state *state;
103 * FIXME. Ha ha ha... This is so wrong.
104 * I'm pulling in data from the check_null_deref script.
105 * I just happen to know that its ID is 3.
106 * The correct approved way to do this is to get the data from
107 * smatch_extra. But right now smatch_extra doesn't track it.
109 state = get_state(name, 3, sym);
110 if (state && !strcmp(state->name, "isnull"))
111 return 1;
112 return 0;
115 static void match_kfree(struct expression *expr)
117 struct expression *ptr_expr;
118 char *fn_name;
119 char *ptr_name;
120 struct symbol *ptr_sym;
123 fn_name = get_variable_from_expr(expr->fn, NULL);
125 if (!fn_name || strcmp(fn_name, "kfree")) {
126 free_string(fn_name);
127 return;
130 ptr_expr = get_argument_from_call_expr(expr->args, 0);
131 ptr_name = get_variable_from_expr(ptr_expr, &ptr_sym);
132 if (is_freed(ptr_name, ptr_sym) && !is_null(ptr_name, ptr_sym)) {
133 smatch_msg("double free of %s", ptr_name);
135 set_state(ptr_name, my_id, ptr_sym, &isfree);
136 free_string(ptr_name);
137 free_string(fn_name);
140 static int possibly_allocated(struct state_list *slist)
142 struct sm_state *tmp;
144 FOR_EACH_PTR(slist, tmp) {
145 if (tmp->state == &allocated)
146 return 1;
147 } END_FOR_EACH_PTR(tmp);
148 return 0;
151 static void check_for_allocated()
153 struct state_list *slist;
154 struct sm_state *tmp;
156 return;
158 slist = get_all_states(my_id);
159 FOR_EACH_PTR(slist, tmp) {
160 if (possibly_allocated(tmp->possible) &&
161 !is_null(tmp->name, tmp->sym))
162 smatch_msg("possible memery leak of %s", tmp->name);
163 } END_FOR_EACH_PTR(tmp);
164 free_slist(&slist);
167 static void match_return(struct statement *stmt)
169 char *name;
170 struct symbol *sym;
171 struct smatch_state *state;
173 name = get_variable_from_expr(stmt->ret_value, &sym);
174 if ((state = get_state(name, my_id, sym))) {
175 set_state(name, my_id, sym, &returned);
177 free_string(name);
178 check_for_allocated();
181 static void match_function_call(struct expression *expr)
188 static void match_end_func(struct symbol *sym)
190 check_for_allocated();
193 void register_memory(int id)
195 my_id = id;
196 add_hook(&match_kfree, FUNCTION_CALL_HOOK);
197 add_hook(&match_assign, ASSIGNMENT_HOOK);
198 add_hook(&match_return, RETURN_HOOK);
199 add_hook(&match_end_func, END_FUNC_HOOK);