2 * sparse/check_locking.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
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.
22 #include "smatch_slist.h"
24 static const char *lock_funcs
[] = {
30 "_spin_lock_irqsave_nested",
37 "_write_lock_irqsave",
44 static const char *unlock_funcs
[] = {
46 "_spin_unlock_irqrestore",
51 "_read_unlock_irqrestore",
55 "_write_unlock_irqrestore",
67 static struct locked_call lock_needed
[] = {
68 {"tty_ldisc_ref_wait", "tty_ldisc_lock"},
77 * merge_func() can go away when we fix the core to just store all the possible
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
)
94 static char kernel
[] = "kernel";
95 static char *match_lock_func(char *fn_name
, struct expression_list
*args
)
97 struct expression
*lock_expr
;
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"))
111 static char *match_unlock_func(char *fn_name
, struct expression_list
*args
)
113 struct expression
*lock_expr
;
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"))
127 static void check_locks_needed(const char *fn_name
)
129 struct smatch_state
*state
;
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
)
149 fn_name
= get_variable_from_expr(expr
->fn
, NULL
);
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
);
158 check_locks_needed(fn_name
);
159 free_string(fn_name
);
163 static void match_condition(struct expression
*expr
)
165 /* __raw_spin_is_locked */
168 static int possibly_negative(struct expression
*expr
)
172 struct state_list
*slist
;
173 struct sm_state
*tmp
;
175 name
= get_variable_from_expr(expr
, &sym
);
178 slist
= get_possible_states(name
, SMATCH_EXTRA
, sym
);
179 FOR_EACH_PTR(slist
, tmp
) {
182 if (tmp
->state
->data
)
183 value
= *(int *)tmp
->state
->data
;
188 } END_FOR_EACH_PTR(tmp
);
192 static void match_return(struct statement
*stmt
)
195 struct state_list
*slist
;
196 struct sm_state
*tmp
;
198 ret_val
= get_value(stmt
->ret_value
);
202 if (ret_val
== UNDEFINED
) {
203 if (!possibly_negative(stmt
->ret_value
))
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",
212 } END_FOR_EACH_PTR(tmp
);
215 void register_locking(int id
)
218 add_merge_hook(my_id
, &merge_func
);
219 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
220 add_hook(&match_return
, RETURN_HOOK
);