Add check to look for double frees.
[smatch.git] / check_locking.c
blob20c6ba4c91ebb37955e886dcbd36c0370c01b9b1
1 /*
2 * sparse/check_locking.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * For this test let's look for functions that return a negative value
12 * with a spinlock held.
14 * One short coming is that it assumes a function isn't supposed
15 * to return negative with a lock held. Perhaps the function was
16 * called with the lock held. A more complicated script could check that.
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_slist.h"
24 static const char *lock_funcs[] = {
25 "_spin_lock",
26 "down",
27 NULL,
30 static const char *unlock_funcs[] = {
31 "_spin_unlock",
32 "up",
33 NULL,
36 static int my_id;
38 STATE(locked);
39 STATE(unlocked);
42 * merge_func() can go away when we fix the core to just store all the possible
43 * states.
45 * The parameters are passed in alphabetical order with NULL at the beginning
46 * of the alphabet. (s2 is never NULL).
49 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
50 struct smatch_state *s1,
51 struct smatch_state *s2)
53 if (s1 == NULL)
54 return s2;
55 return &undefined;
59 static char *match_lock_func(char *fn_name, struct expression_list *args)
61 struct expression *lock_expr;
62 int i;
64 for (i = 0; lock_funcs[i]; i++) {
65 if (!strcmp(fn_name, lock_funcs[i])) {
66 lock_expr = get_argument_from_call_expr(args, 0);
67 return get_variable_from_expr(lock_expr, NULL);
70 if (!strcmp(fn_name, "lock_kernel"))
71 return "kernel";
72 return NULL;
75 static char *match_unlock_func(char *fn_name, struct expression_list *args)
77 struct expression *lock_expr;
78 int i;
80 for (i = 0; unlock_funcs[i]; i++) {
81 if (!strcmp(fn_name, unlock_funcs[i])) {
82 lock_expr = get_argument_from_call_expr(args, 0);
83 return get_variable_from_expr(lock_expr, NULL);
86 if (!strcmp(fn_name, "unlock_kernel"))
87 return "kernel";
88 return NULL;
91 static void match_call(struct expression *expr)
93 char *fn_name;
94 char *lock_name;
96 fn_name = get_variable_from_expr(expr->fn, NULL);
97 if (!fn_name)
98 return;
100 if ((lock_name = match_lock_func(fn_name, expr->args))) {
101 set_state(lock_name, my_id, NULL, &locked);
102 } else if ((lock_name = match_unlock_func(fn_name, expr->args))) {
103 set_state(lock_name, my_id, NULL, &unlocked);
105 free_string(fn_name);
106 return;
109 static void match_condition(struct expression *expr)
111 /* __raw_spin_is_locked */
114 static int possibly_negative(struct expression *expr)
116 char *name;
117 struct symbol *sym;
118 struct state_list *slist;
119 struct sm_state *tmp;
121 name = get_variable_from_expr(expr, &sym);
122 if (!name || !sym)
123 return 0;
124 slist = get_possible_states(name, SMATCH_EXTRA, sym);
125 FOR_EACH_PTR(slist, tmp) {
126 int value = 0;
128 if (tmp->state->data)
129 value = *(int *)tmp->state->data;
131 if (value < 0) {
132 return 1;
134 } END_FOR_EACH_PTR(tmp);
135 return 0;
138 static void match_return(struct statement *stmt)
140 int ret_val;
141 struct state_list *slist;
142 struct sm_state *tmp;
144 ret_val = get_value(stmt->ret_value);
145 if (ret_val >= 0) {
146 return;
148 if (ret_val == UNDEFINED) {
149 if (!possibly_negative(stmt->ret_value))
150 return;
153 slist = get_all_states(my_id);
154 FOR_EACH_PTR(slist, tmp) {
155 if (tmp->state != &unlocked)
156 smatch_msg("returned negative with %s lock held",
157 tmp->name);
158 } END_FOR_EACH_PTR(tmp);
161 void register_locking(int id)
163 my_id = id;
164 add_merge_hook(my_id, &merge_func);
165 add_hook(&match_call, FUNCTION_CALL_HOOK);
166 add_hook(&match_return, RETURN_HOOK);