2 * sparse/check_memory.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
12 #include "smatch_slist.h"
22 static const char *allocation_funcs
[] = {
28 static int is_allocation(struct expression
*expr
)
33 if (expr
->type
!= EXPR_CALL
)
36 if (!(fn_name
= get_variable_from_expr(expr
->fn
, NULL
)))
39 for (i
= 0; allocation_funcs
[i
]; i
++) {
40 if (!strcmp(fn_name
, allocation_funcs
[i
])) {
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
)) {
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
);
72 free_string(left_name
);
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
);
83 right_name
= get_variable_from_expr(right
, &right_sym
);
84 if (right_name
&& (state
= get_state(right_name
, my_id
, right_sym
))) {
86 smatch_msg("assigning freed pointer");
87 set_state(right_name
, my_id
, right_sym
, &assigned
);
89 free_string(right_name
);
91 if (is_freed(left_name
, left_sym
)) {
92 set_state(left_name
, my_id
, left_sym
, &unfree
);
96 static int is_null(char *name
, struct symbol
*sym
)
98 struct smatch_state
*state
;
101 * FIXME. Ha ha ha... This is so wrong.
102 * I'm pulling in data from the check_null_deref script.
103 * I just happen to know that its ID is 3.
104 * The correct approved way to do this is to get the data from
105 * smatch_extra. But right now smatch_extra doesn't track it.
107 state
= get_state(name
, 3, sym
);
108 if (state
&& !strcmp(state
->name
, "isnull"))
113 static void match_kfree(struct expression
*expr
)
115 struct expression
*ptr_expr
;
118 struct symbol
*ptr_sym
;
121 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
123 if (!fn_name
|| strcmp(fn_name
, "kfree"))
126 ptr_expr
= get_argument_from_call_expr(expr
->args
, 0);
127 ptr_name
= get_variable_from_expr(ptr_expr
, &ptr_sym
);
128 if (is_freed(ptr_name
, ptr_sym
) && !is_null(ptr_name
, ptr_sym
)) {
129 smatch_msg("double free of %s", ptr_name
);
131 set_state(ptr_name
, my_id
, ptr_sym
, &isfree
);
133 free_string(fn_name
);
136 static int possibly_allocated(struct state_list
*slist
)
138 struct sm_state
*tmp
;
140 FOR_EACH_PTR(slist
, tmp
) {
141 if (tmp
->state
== &allocated
)
143 } END_FOR_EACH_PTR(tmp
);
147 static void check_for_allocated()
149 struct state_list
*slist
;
150 struct sm_state
*tmp
;
154 slist
= get_all_states(my_id
);
155 FOR_EACH_PTR(slist
, tmp
) {
156 if (possibly_allocated(tmp
->possible
) &&
157 !is_null(tmp
->name
, tmp
->sym
))
158 smatch_msg("possible memery leak of %s", tmp
->name
);
159 } END_FOR_EACH_PTR(tmp
);
163 static void match_return(struct statement
*stmt
)
167 struct smatch_state
*state
;
169 name
= get_variable_from_expr(stmt
->ret_value
, &sym
);
170 if ((state
= get_state(name
, my_id
, sym
))) {
171 set_state(name
, my_id
, sym
, &returned
);
174 check_for_allocated();
177 static void match_function_call(struct expression
*expr
)
184 static void match_end_func(struct symbol
*sym
)
186 check_for_allocated();
189 void register_memory(int id
)
192 add_hook(&match_kfree
, FUNCTION_CALL_HOOK
);
193 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
194 add_hook(&match_return
, RETURN_HOOK
);
195 add_hook(&match_end_func
, END_FUNC_HOOK
);