Oops. ->possibles wasn't getting set correctly.
[smatch.git] / check_memory.c
blob5a8df3a2619a1a335c4ffafc2a554d66b5483f22
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 void match_assign(struct expression *expr)
51 struct expression *left, *right;
52 char *left_name, *right_name;
53 struct symbol *left_sym, *right_sym;
54 struct smatch_state *state;
56 left = strip_expr(expr->left);
57 left_name = get_variable_from_expr(left, &left_sym);
58 if (!left_name)
59 return;
60 if (!left_sym) {
61 free_string(left_name);
62 return;
65 right = strip_expr(expr->right);
66 if (is_allocation(right)) {
67 if (left_sym->ctype.modifiers &
68 (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))
69 return;
70 set_state(left_name, my_id, left_sym, &allocated);
71 return;
74 right_name = get_variable_from_expr(right, &right_sym);
75 if (right_name && (state = get_state(right_name, my_id, right_sym))) {
76 if (state == &isfree)
77 smatch_msg("assigning freed pointer");
78 set_state(right_name, my_id, right_sym, &assigned);
79 free_string(right_name);
80 return;
82 free_string(right_name);
84 if (is_zero(right))
85 return;
87 if (get_state(left_name, my_id, left_sym) == &isfree) {
88 set_state(left_name, my_id, left_sym, &unfree);
92 static int is_null(char *name, struct symbol *sym)
94 struct smatch_state *state;
96 /*
97 * FIXME. Ha ha ha... This is so wrong.
98 * I'm pulling in data from the check_null_deref script.
99 * I just happen to know that its ID is 3.
100 * The correct approved way to do this is to get the data from
101 * smatch_extra. But right now smatch_extra doesn't track it.
103 state = get_state(name, 3, sym);
104 if (state && !strcmp(state->name, "isnull"))
105 return 1;
106 return 0;
109 static void match_kfree(struct expression *expr)
111 struct expression *ptr_expr;
112 struct state_list *slist;
113 char *fn_name;
114 char *ptr_name;
115 struct symbol *ptr_sym;
118 fn_name = get_variable_from_expr(expr->fn, NULL);
120 if (!fn_name || strcmp(fn_name, "kfree"))
121 return;
123 ptr_expr = get_argument_from_call_expr(expr->args, 0);
124 ptr_name = get_variable_from_expr(ptr_expr, &ptr_sym);
125 slist = get_possible_states(ptr_name, my_id, ptr_sym);
126 if (slist_has_state(slist, &isfree) && !is_null(ptr_name, ptr_sym)) {
127 smatch_msg("double free of %s", ptr_name);
129 set_state(ptr_name, my_id, ptr_sym, &isfree);
131 free_string(fn_name);
134 static int possibly_allocated(struct state_list *slist)
136 struct sm_state *tmp;
138 FOR_EACH_PTR(slist, tmp) {
139 if (tmp->state == &allocated)
140 return 1;
141 } END_FOR_EACH_PTR(tmp);
142 return 0;
145 static void check_for_allocated()
147 struct state_list *slist;
148 struct sm_state *tmp;
150 slist = get_all_states(my_id);
151 FOR_EACH_PTR(slist, tmp) {
152 if (possibly_allocated(tmp->possible) &&
153 !is_null(tmp->name, tmp->sym))
154 smatch_msg("possible memery leak of %s", tmp->name);
155 } END_FOR_EACH_PTR(tmp);
159 static void match_return(struct statement *stmt)
161 char *name;
162 struct symbol *sym;
163 struct smatch_state *state;
165 name = get_variable_from_expr(stmt->ret_value, &sym);
166 if ((state = get_state(name, my_id, sym))) {
167 set_state(name, my_id, sym, &returned);
170 check_for_allocated();
173 static void match_function_call(struct expression *expr)
180 static void match_end_func(struct symbol *sym)
182 check_for_allocated();
185 void register_memory(int id)
187 my_id = id;
188 add_hook(&match_kfree, FUNCTION_CALL_HOOK);
189 add_hook(&match_assign, ASSIGNMENT_HOOK);
190 add_hook(&match_return, RETURN_HOOK);
191 add_hook(&match_end_func, END_FUNC_HOOK);