Fix usage message.
[smatch.git] / check_memory.c
blobadceb500f0e3e5775b24287be1c82b596bbb9c25
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 & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE))
68 return;
69 set_state(left_name, my_id, left_sym, &allocated);
70 return;
73 right_name = get_variable_from_expr(right, &right_sym);
74 if (right_name && (state = get_state(right_name, my_id, right_sym))) {
75 if (state == &isfree)
76 smatch_msg("assigning freed pointer");
77 set_state(right_name, my_id, right_sym, &assigned);
78 free_string(right_name);
79 return;
81 free_string(right_name);
83 if (is_zero(right))
84 return;
86 if (get_state(left_name, my_id, left_sym) == &isfree) {
87 set_state(left_name, my_id, left_sym, &unfree);
91 static int is_null(char *name, struct symbol *sym)
93 struct smatch_state *state;
95 /*
96 * FIXME. Ha ha ha... This is so wrong.
97 * I'm pulling in data from the check_null_deref script.
98 * I just happen to know that its ID is 3.
99 * The correct approved way to do this is to get the data from
100 * smatch_extra. But right now smatch_extra doesn't track it.
102 state = get_state(name, 3, sym);
103 if (state && !strcmp(state->name, "isnull"))
104 return 1;
105 return 0;
108 static void match_kfree(struct expression *expr)
110 struct expression *ptr_expr;
111 struct state_list *slist;
112 char *fn_name;
113 char *ptr_name;
114 struct symbol *ptr_sym;
117 fn_name = get_variable_from_expr(expr->fn, NULL);
119 if (!fn_name || strcmp(fn_name, "kfree"))
120 return;
122 ptr_expr = get_argument_from_call_expr(expr->args, 0);
123 ptr_name = get_variable_from_expr(ptr_expr, &ptr_sym);
124 slist = get_possible_states(ptr_name, my_id, ptr_sym);
125 if (slist_has_state(slist, &isfree) && !is_null(ptr_name, ptr_sym)) {
126 smatch_msg("double free of %s", ptr_name);
128 set_state(ptr_name, my_id, ptr_sym, &isfree);
130 free_string(fn_name);
133 static int possibly_allocated(struct state_list *slist)
135 struct sm_state *tmp;
137 FOR_EACH_PTR(slist, tmp) {
138 if (tmp->state == &allocated)
139 return 1;
140 } END_FOR_EACH_PTR(tmp);
141 return 0;
144 static void check_for_allocated()
146 struct state_list *slist;
147 struct sm_state *tmp;
149 slist = get_all_states(my_id);
150 FOR_EACH_PTR(slist, tmp) {
151 if (possibly_allocated(tmp->possible) &&
152 !is_null(tmp->name, tmp->sym))
153 smatch_msg("possible memery leak of %s", tmp->name);
154 } END_FOR_EACH_PTR(tmp);
158 static void match_return(struct statement *stmt)
160 char *name;
161 struct symbol *sym;
162 struct smatch_state *state;
164 name = get_variable_from_expr(stmt->ret_value, &sym);
165 if ((state = get_state(name, my_id, sym))) {
166 set_state(name, my_id, sym, &returned);
169 check_for_allocated();
172 static void match_end_func(struct symbol *sym)
174 check_for_allocated();
177 void register_memory(int id)
179 my_id = id;
180 add_hook(&match_kfree, FUNCTION_CALL_HOOK);
181 add_hook(&match_assign, ASSIGNMENT_HOOK);
182 add_hook(&match_return, RETURN_HOOK);
183 add_hook(&match_end_func, END_FUNC_HOOK);