"while ((1)) {" is a forever loop. Call strip_expr().
[smatch.git] / check_locking.c
blobfd8c15f11e55be1c5531480d2f266523a9139413
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 "_spin_lock_irqsave",
27 "_spin_lock_irq",
28 "_spin_lock_bh",
29 "_spin_lock_nested",
30 "_spin_lock_irqsave_nested",
31 "_raw_spin_lock",
32 "_read_lock",
33 "_read_lock_irqsave",
34 "_read_lock_irq",
35 "_read_lock_bh",
36 "_write_lock",
37 "_write_lock_irqsave",
38 "_write_lock_irq",
39 "_write_lock_bh",
40 "down",
41 NULL,
44 static const char *unlock_funcs[] = {
45 "_spin_unlock",
46 "_spin_unlock_irqrestore",
47 "_spin_unlock_irq",
48 "_spin_unlock_bh",
49 "_raw_spin_unlock",
50 "_read_unlock",
51 "_read_unlock_irqrestore",
52 "_read_unlock_irq",
53 "_read_unlock_bh",
54 "_write_unlock",
55 "_write_unlock_irqrestore",
56 "_write_unlock_irq",
57 "_write_unlock_bh",
58 "up",
59 NULL,
62 struct locked_call {
63 const char *function;
64 const char *lock;
67 static struct locked_call lock_needed[] = {
68 {"tty_ldisc_ref_wait", "tty_ldisc_lock"},
71 static int my_id;
73 STATE(locked);
74 STATE(unlocked);
77 * merge_func() can go away when we fix the core to just store all the possible
78 * states.
80 * The parameters are passed in alphabetical order with NULL at the beginning
81 * of the alphabet. (s2 is never NULL).
84 static struct smatch_state *merge_func(const char *name, struct symbol *sym,
85 struct smatch_state *s1,
86 struct smatch_state *s2)
88 if (s1 == NULL)
89 return s2;
90 return &undefined;
94 static char kernel[] = "kernel";
95 static char *match_lock_func(char *fn_name, struct expression_list *args)
97 struct expression *lock_expr;
98 int i;
100 for (i = 0; lock_funcs[i]; i++) {
101 if (!strcmp(fn_name, lock_funcs[i])) {
102 lock_expr = get_argument_from_call_expr(args, 0);
103 return get_variable_from_expr(lock_expr, NULL);
106 if (!strcmp(fn_name, "lock_kernel"))
107 return kernel;
108 return NULL;
111 static char *match_unlock_func(char *fn_name, struct expression_list *args)
113 struct expression *lock_expr;
114 int i;
116 for (i = 0; unlock_funcs[i]; i++) {
117 if (!strcmp(fn_name, unlock_funcs[i])) {
118 lock_expr = get_argument_from_call_expr(args, 0);
119 return get_variable_from_expr(lock_expr, NULL);
122 if (!strcmp(fn_name, "unlock_kernel"))
123 return kernel;
124 return NULL;
127 static void check_locks_needed(const char *fn_name)
129 struct smatch_state *state;
130 int i;
132 for (i = 0; i < sizeof(lock_needed)/sizeof(struct locked_call); i++) {
133 if (!strcmp(fn_name, lock_needed[i].function)) {
134 state = get_state(lock_needed[i].lock, my_id, NULL);
135 if (state != &locked) {
136 smatch_msg("%s called without holding %s lock",
137 lock_needed[i].function,
138 lock_needed[i].lock);
144 static void match_call(struct expression *expr)
146 char *fn_name;
147 char *lock_name;
149 fn_name = get_variable_from_expr(expr->fn, NULL);
150 if (!fn_name)
151 return;
153 if ((lock_name = match_lock_func(fn_name, expr->args)))
154 set_state(lock_name, my_id, NULL, &locked);
155 else if ((lock_name = match_unlock_func(fn_name, expr->args)))
156 set_state(lock_name, my_id, NULL, &unlocked);
157 else
158 check_locks_needed(fn_name);
159 free_string(fn_name);
160 return;
163 static void match_condition(struct expression *expr)
165 /* __raw_spin_is_locked */
168 static int possibly_negative(struct expression *expr)
170 char *name;
171 struct symbol *sym;
172 struct state_list *slist;
173 struct sm_state *tmp;
175 name = get_variable_from_expr(expr, &sym);
176 if (!name || !sym)
177 return 0;
178 slist = get_possible_states(name, SMATCH_EXTRA, sym);
179 FOR_EACH_PTR(slist, tmp) {
180 int value = 0;
182 if (tmp->state->data)
183 value = *(int *)tmp->state->data;
185 if (value < 0) {
186 return 1;
188 } END_FOR_EACH_PTR(tmp);
189 return 0;
192 static void match_return(struct statement *stmt)
194 int ret_val;
195 struct state_list *slist;
196 struct sm_state *tmp;
198 ret_val = get_value(stmt->ret_value);
199 if (ret_val >= 0) {
200 return;
202 if (ret_val == UNDEFINED) {
203 if (!possibly_negative(stmt->ret_value))
204 return;
207 slist = get_all_states(my_id);
208 FOR_EACH_PTR(slist, tmp) {
209 if (tmp->state != &unlocked)
210 smatch_msg("returned negative with %s lock held",
211 tmp->name);
212 } END_FOR_EACH_PTR(tmp);
215 void register_locking(int id)
217 my_id = id;
218 add_merge_hook(my_id, &merge_func);
219 add_hook(&match_call, FUNCTION_CALL_HOOK);
220 add_hook(&match_return, RETURN_HOOK);