function_hooks/check_unwind: add param_key_hooks
[smatch.git] / check_locking.c
blob994cd7cd0a369845ca5b96c05afafb9c7717ca55
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
3 * Copyright (C) 2019 Oracle.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include <ctype.h>
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_extra.h"
23 #include "smatch_slist.h"
25 static int my_id;
27 STATE(locked);
28 STATE(half_locked);
29 STATE(start_state);
30 STATE(unlocked);
31 STATE(impossible);
32 STATE(restore);
34 enum action {
35 LOCK,
36 UNLOCK,
37 RESTORE,
40 enum lock_type {
41 spin_lock,
42 read_lock,
43 write_lock,
44 mutex,
45 bottom_half,
46 irq,
47 sem,
48 prepare_lock,
49 enable_lock,
50 rcu,
51 rcu_read,
54 const char *get_lock_name(enum lock_type type)
56 static const char *names[] = {
57 [spin_lock] = "spin_lock",
58 [read_lock] = "read_lock",
59 [write_lock] = "write_lock",
60 [mutex] = "mutex",
61 [bottom_half] = "bottom_half",
62 [irq] = "irq",
63 [sem] = "sem",
64 [prepare_lock] = "prepare_lock",
65 [enable_lock] = "enable_lock",
66 [rcu] = "rcu",
67 [rcu_read] = "rcu_read",
70 return names[type];
73 enum return_type {
74 ret_any,
75 ret_zero,
76 ret_one,
77 ret_negative,
78 ret_positive,
79 ret_valid_ptr,
82 #define RETURN_VAL -1
83 #define NO_ARG -2
85 struct lock_info {
86 const char *function;
87 enum action action;
88 enum lock_type type;
89 int arg;
90 enum return_type return_type;
93 static struct lock_info lock_table[] = {
94 {"spin_lock", LOCK, spin_lock, 0, ret_any},
95 {"spin_unlock", UNLOCK, spin_lock, 0, ret_any},
96 {"spin_lock_nested", LOCK, spin_lock, 0, ret_any},
97 {"_spin_lock", LOCK, spin_lock, 0, ret_any},
98 {"_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
99 {"_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
100 {"__spin_lock", LOCK, spin_lock, 0, ret_any},
101 {"__spin_unlock", UNLOCK, spin_lock, 0, ret_any},
102 {"__spin_lock_nested", LOCK, spin_lock, 0, ret_any},
103 {"raw_spin_lock", LOCK, spin_lock, 0, ret_any},
104 {"raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
105 {"_raw_spin_lock", LOCK, spin_lock, 0, ret_any},
106 {"_raw_spin_lock_nested", LOCK, spin_lock, 0, ret_any},
107 {"_raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
108 {"__raw_spin_lock", LOCK, spin_lock, 0, ret_any},
109 {"__raw_spin_unlock", UNLOCK, spin_lock, 0, ret_any},
111 {"spin_lock_irq", LOCK, spin_lock, 0, ret_any},
112 {"spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
113 {"_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
114 {"_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
115 {"__spin_lock_irq", LOCK, spin_lock, 0, ret_any},
116 {"__spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
117 {"_raw_spin_lock_irq", LOCK, spin_lock, 0, ret_any},
118 {"_raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
119 {"__raw_spin_unlock_irq", UNLOCK, spin_lock, 0, ret_any},
120 {"spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
121 {"spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
122 {"_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
123 {"_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
124 {"__spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
125 {"__spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
126 {"_raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
127 {"_raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
128 {"__raw_spin_lock_irqsave", LOCK, spin_lock, 0, ret_any},
129 {"__raw_spin_unlock_irqrestore", UNLOCK, spin_lock, 0, ret_any},
130 {"spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
131 {"_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
132 {"__spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
133 {"_raw_spin_lock_irqsave_nested", LOCK, spin_lock, 0, ret_any},
134 {"spin_lock_bh", LOCK, spin_lock, 0, ret_any},
135 {"spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
136 {"_spin_lock_bh", LOCK, spin_lock, 0, ret_any},
137 {"_spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
138 {"__spin_lock_bh", LOCK, spin_lock, 0, ret_any},
139 {"__spin_unlock_bh", UNLOCK, spin_lock, 0, ret_any},
141 {"spin_trylock", LOCK, spin_lock, 0, ret_one},
142 {"_spin_trylock", LOCK, spin_lock, 0, ret_one},
143 {"__spin_trylock", LOCK, spin_lock, 0, ret_one},
144 {"raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
145 {"_raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
146 {"spin_trylock_irq", LOCK, spin_lock, 0, ret_one},
147 {"spin_trylock_irqsave", LOCK, spin_lock, 0, ret_one},
148 {"spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
149 {"_spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
150 {"__spin_trylock_bh", LOCK, spin_lock, 0, ret_one},
151 {"__raw_spin_trylock", LOCK, spin_lock, 0, ret_one},
152 {"_atomic_dec_and_lock", LOCK, spin_lock, 1, ret_one},
154 {"read_lock", LOCK, read_lock, 0, ret_any},
155 {"down_read", LOCK, read_lock, 0, ret_any},
156 {"down_read_nested", LOCK, read_lock, 0, ret_any},
157 {"down_read_trylock", LOCK, read_lock, 0, ret_one},
158 {"down_read_killable", LOCK, read_lock, 0, ret_zero},
159 {"up_read", UNLOCK, read_lock, 0, ret_any},
160 {"read_unlock", UNLOCK, read_lock, 0, ret_any},
161 {"_read_lock", LOCK, read_lock, 0, ret_any},
162 {"_read_unlock", UNLOCK, read_lock, 0, ret_any},
163 {"__read_lock", LOCK, read_lock, 0, ret_any},
164 {"__read_unlock", UNLOCK, read_lock, 0, ret_any},
165 {"_raw_read_lock", LOCK, read_lock, 0, ret_any},
166 {"_raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
167 {"__raw_read_lock", LOCK, read_lock, 0, ret_any},
168 {"__raw_read_unlock", UNLOCK, read_lock, 0, ret_any},
169 {"read_lock_irq", LOCK, read_lock, 0, ret_any},
170 {"read_unlock_irq" , UNLOCK, read_lock, 0, ret_any},
171 {"_read_lock_irq", LOCK, read_lock, 0, ret_any},
172 {"_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
173 {"__read_lock_irq", LOCK, read_lock, 0, ret_any},
174 {"__read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
175 {"_raw_read_unlock_irq", UNLOCK, read_lock, 0, ret_any},
176 {"_raw_read_lock_irq", LOCK, read_lock, 0, ret_any},
177 {"_raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
178 {"_raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
179 {"read_lock_irqsave", LOCK, read_lock, 0, ret_any},
180 {"read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
181 {"_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
182 {"_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
183 {"__read_lock_irqsave", LOCK, read_lock, 0, ret_any},
184 {"__read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
185 {"read_lock_bh", LOCK, read_lock, 0, ret_any},
186 {"read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
187 {"_read_lock_bh", LOCK, read_lock, 0, ret_any},
188 {"_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
189 {"__read_lock_bh", LOCK, read_lock, 0, ret_any},
190 {"__read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
191 {"__raw_read_lock_bh", LOCK, read_lock, 0, ret_any},
192 {"__raw_read_unlock_bh", UNLOCK, read_lock, 0, ret_any},
194 {"_raw_read_lock_irqsave", LOCK, read_lock, 0, ret_any},
195 {"_raw_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
196 {"_raw_read_unlock_irqrestore", UNLOCK, read_lock, 0, ret_any},
197 {"_raw_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
198 {"_raw_spin_lock_bh", LOCK, read_lock, 0, ret_any},
199 {"_raw_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
200 {"_raw_spin_lock_nest_lock", LOCK, read_lock, 0, ret_any},
201 {"_raw_spin_unlock_bh", UNLOCK, read_lock, 0, ret_any},
202 {"_raw_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
203 {"_raw_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
204 {"_raw_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
205 {"_raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
206 {"_raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
207 {"__raw_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
208 {"__raw_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
210 {"generic__raw_read_trylock", LOCK, read_lock, 0, ret_one},
211 {"read_trylock", LOCK, read_lock, 0, ret_one},
212 {"_read_trylock", LOCK, read_lock, 0, ret_one},
213 {"raw_read_trylock", LOCK, read_lock, 0, ret_one},
214 {"_raw_read_trylock", LOCK, read_lock, 0, ret_one},
215 {"__raw_read_trylock", LOCK, read_lock, 0, ret_one},
216 {"__read_trylock", LOCK, read_lock, 0, ret_one},
218 {"write_lock", LOCK, write_lock, 0, ret_any},
219 {"down_write", LOCK, write_lock, 0, ret_any},
220 {"down_write_nested", LOCK, write_lock, 0, ret_any},
221 {"up_write", UNLOCK, write_lock, 0, ret_any},
222 {"write_unlock", UNLOCK, write_lock, 0, ret_any},
223 {"_write_lock", LOCK, write_lock, 0, ret_any},
224 {"_write_unlock", UNLOCK, write_lock, 0, ret_any},
225 {"__write_lock", LOCK, write_lock, 0, ret_any},
226 {"__write_unlock", UNLOCK, write_lock, 0, ret_any},
227 {"write_lock_irq", LOCK, write_lock, 0, ret_any},
228 {"write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
229 {"_write_lock_irq", LOCK, write_lock, 0, ret_any},
230 {"_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
231 {"__write_lock_irq", LOCK, write_lock, 0, ret_any},
232 {"__write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
233 {"_raw_write_unlock_irq", UNLOCK, write_lock, 0, ret_any},
234 {"write_lock_irqsave", LOCK, write_lock, 0, ret_any},
235 {"write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
236 {"_write_lock_irqsave", LOCK, write_lock, 0, ret_any},
237 {"_write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
238 {"__write_lock_irqsave", LOCK, write_lock, 0, ret_any},
239 {"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
240 {"write_lock_bh", LOCK, write_lock, 0, ret_any},
241 {"write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
242 {"_write_lock_bh", LOCK, write_lock, 0, ret_any},
243 {"_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
244 {"__write_lock_bh", LOCK, write_lock, 0, ret_any},
245 {"__write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
246 {"_raw_write_lock", LOCK, write_lock, 0, ret_any},
247 {"__raw_write_lock", LOCK, write_lock, 0, ret_any},
248 {"_raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
249 {"__raw_write_unlock", UNLOCK, write_lock, 0, ret_any},
250 {"_raw_write_lock_bh", LOCK, write_lock, 0, ret_any},
251 {"_raw_write_unlock_bh", UNLOCK, write_lock, 0, ret_any},
252 {"_raw_write_lock_irq", LOCK, write_lock, 0, ret_any},
254 {"write_trylock", LOCK, write_lock, 0, ret_one},
255 {"_write_trylock", LOCK, write_lock, 0, ret_one},
256 {"raw_write_trylock", LOCK, write_lock, 0, ret_one},
257 {"_raw_write_trylock", LOCK, write_lock, 0, ret_one},
258 {"__write_trylock", LOCK, write_lock, 0, ret_one},
259 {"__raw_write_trylock", LOCK, write_lock, 0, ret_one},
260 {"down_write_trylock", LOCK, write_lock, 0, ret_one},
261 {"down_write_killable", LOCK, write_lock, 0, ret_zero},
263 {"down", LOCK, sem, 0, ret_any},
264 {"up", UNLOCK, sem, 0, ret_any},
265 {"down_trylock", LOCK, sem, 0, ret_zero},
266 {"down_timeout", LOCK, sem, 0, ret_zero},
267 {"down_interruptible", LOCK, sem, 0, ret_zero},
268 {"down_killable", LOCK, sem, 0, ret_zero},
271 {"mutex_lock", LOCK, mutex, 0, ret_any},
272 {"mutex_unlock", UNLOCK, mutex, 0, ret_any},
273 {"mutex_destroy", RESTORE, mutex, 0, ret_any},
274 {"mutex_lock_nested", LOCK, mutex, 0, ret_any},
275 {"mutex_lock_io", LOCK, mutex, 0, ret_any},
276 {"mutex_lock_io_nested", LOCK, mutex, 0, ret_any},
278 {"mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
279 {"mutex_lock_interruptible_nested", LOCK, mutex, 0, ret_zero},
280 {"mutex_lock_killable", LOCK, mutex, 0, ret_zero},
281 {"mutex_lock_killable_nested", LOCK, mutex, 0, ret_zero},
283 {"mutex_trylock", LOCK, mutex, 0, ret_one},
285 {"ww_mutex_lock", LOCK, mutex, 0, ret_any},
286 {"__ww_mutex_lock", LOCK, mutex, 0, ret_any},
287 {"ww_mutex_lock_interruptible", LOCK, mutex, 0, ret_zero},
288 {"ww_mutex_unlock", UNLOCK, mutex, 0, ret_any},
290 {"raw_local_irq_disable", LOCK, irq, NO_ARG, ret_any},
291 {"raw_local_irq_enable", UNLOCK, irq, NO_ARG, ret_any},
292 {"spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
293 {"spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
294 {"_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
295 {"_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
296 {"__spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
297 {"__spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
298 {"_raw_spin_lock_irq", LOCK, irq, NO_ARG, ret_any},
299 {"_raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
300 {"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
301 {"spin_trylock_irq", LOCK, irq, NO_ARG, ret_one},
302 {"read_lock_irq", LOCK, irq, NO_ARG, ret_any},
303 {"read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
304 {"_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
305 {"_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
306 {"__read_lock_irq", LOCK, irq, NO_ARG, ret_any},
307 {"_raw_read_lock_irq", LOCK, irq, NO_ARG, ret_any},
308 {"__read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
309 {"_raw_read_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
310 {"write_lock_irq", LOCK, irq, NO_ARG, ret_any},
311 {"write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
312 {"_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
313 {"_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
314 {"__write_lock_irq", LOCK, irq, NO_ARG, ret_any},
315 {"__write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
316 {"_raw_write_lock_irq", LOCK, irq, NO_ARG, ret_any},
317 {"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
319 {"arch_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
320 {"arch_local_irq_restore", RESTORE, irq, 0, ret_any},
321 {"__raw_local_irq_save", LOCK, irq, RETURN_VAL, ret_any},
322 {"raw_local_irq_restore", RESTORE, irq, 0, ret_any},
323 {"spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
324 {"spin_lock_irqsave", LOCK, irq, 1, ret_any},
325 {"spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
326 {"_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
327 {"_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
328 {"_spin_lock_irqsave", LOCK, irq, 1, ret_any},
329 {"_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
330 {"__spin_lock_irqsave_nested", LOCK, irq, 1, ret_any},
331 {"__spin_lock_irqsave", LOCK, irq, 1, ret_any},
332 {"__spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
333 {"_raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
334 {"_raw_spin_lock_irqsave", LOCK, irq, 1, ret_any},
335 {"_raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
336 {"__raw_spin_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
337 {"__raw_spin_unlock_irqrestore", RESTORE, irq, 1, ret_any},
338 {"_raw_spin_lock_irqsave_nested", LOCK, irq, RETURN_VAL, ret_any},
339 {"spin_trylock_irqsave", LOCK, irq, 1, ret_one},
340 {"read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
341 {"read_lock_irqsave", LOCK, irq, 1, ret_any},
342 {"read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
343 {"_read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
344 {"_read_lock_irqsave", LOCK, irq, 1, ret_any},
345 {"_read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
346 {"__read_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
347 {"__read_unlock_irqrestore", RESTORE, irq, 1, ret_any},
348 {"write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
349 {"write_lock_irqsave", LOCK, irq, 1, ret_any},
350 {"write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
351 {"_write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
352 {"_write_lock_irqsave", LOCK, irq, 1, ret_any},
353 {"_write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
354 {"__write_lock_irqsave", LOCK, irq, RETURN_VAL, ret_any},
355 {"__write_unlock_irqrestore", RESTORE, irq, 1, ret_any},
357 {"local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
358 {"_local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
359 {"__local_bh_disable", LOCK, bottom_half, NO_ARG, ret_any},
360 {"local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
361 {"_local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
362 {"__local_bh_enable", UNLOCK, bottom_half, NO_ARG, ret_any},
363 {"spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
364 {"spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
365 {"_spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
366 {"_spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
367 {"__spin_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
368 {"__spin_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
369 {"read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
370 {"read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
371 {"_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
372 {"_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
373 {"__read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
374 {"__read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
375 {"_raw_read_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
376 {"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
377 {"write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
378 {"write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
379 {"_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
380 {"_write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
381 {"__write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
382 {"__write_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
383 {"_raw_write_lock_bh", LOCK, bottom_half, NO_ARG, ret_any},
384 {"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
385 {"spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
386 {"_spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
387 {"__spin_trylock_bh", LOCK, bottom_half, NO_ARG, ret_one},
389 {"ffs_mutex_lock", LOCK, mutex, 0, ret_zero},
391 {"clk_prepare_lock", LOCK, prepare_lock, NO_ARG, ret_any},
392 {"clk_prepare_unlock", UNLOCK, prepare_lock, NO_ARG, ret_any},
393 {"clk_enable_lock", LOCK, enable_lock, -1, ret_any},
394 {"clk_enable_unlock", UNLOCK, enable_lock, 0, ret_any},
396 {"dma_resv_lock", LOCK, mutex, 0, ret_zero},
397 {"dma_resv_trylock", LOCK, mutex, 0, ret_one},
398 {"dma_resv_lock_interruptible", LOCK, mutex, 0, ret_zero},
399 {"dma_resv_unlock", UNLOCK, mutex, 0, ret_any},
401 {"modeset_lock", LOCK, mutex, 0, ret_zero},
402 {"drm_ modeset_lock", LOCK, mutex, 0, ret_zero},
403 {"drm_modeset_lock_single_interruptible", LOCK, mutex, 0, ret_zero},
404 {"modeset_unlock", UNLOCK, mutex, 0, ret_any},
405 // {"nvkm_i2c_aux_acquire", LOCK, mutex,
406 // {"i915_gem_object_lock_interruptible", LOCK, mutex,
408 {"reiserfs_write_lock_nested", LOCK, mutex, 0, ret_any},
409 {"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
411 {"rw_lock", LOCK, write_lock, 1, ret_any},
412 {"rw_unlock", UNLOCK, write_lock, 1, ret_any},
414 {"sem_lock", LOCK, mutex, 0, ret_any},
415 {"sem_unlock", UNLOCK, mutex, 0, ret_any},
417 {"rcu_lock_acquire", LOCK, rcu, NO_ARG, ret_any},
418 {"rcu_lock_release", UNLOCK, rcu, NO_ARG, ret_any},
420 {"rcu_read_lock", LOCK, rcu_read, NO_ARG, ret_any},
421 {"rcu_read_unlock", UNLOCK, rcu_read, NO_ARG, ret_any},
422 {"rcu_read_lock_bh", LOCK, rcu_read, NO_ARG, ret_any},
423 {"rcu_read_unlock_bh", UNLOCK, rcu_read, NO_ARG, ret_any},
425 {"rcu_read_lock_sched", LOCK, rcu_read, NO_ARG, ret_any},
426 {"rcu_read_lock_sched_notrace", LOCK, rcu_read, NO_ARG, ret_any},
427 {"rcu_read_unlock_sched", UNLOCK, rcu_read, NO_ARG, ret_any},
428 {"rcu_read_unlock_sched_notrace", UNLOCK, rcu_read, NO_ARG, ret_any},
433 struct macro_info {
434 const char *macro;
435 enum action action;
436 int param;
439 static struct macro_info macro_table[] = {
440 {"genpd_lock", LOCK, 0},
441 {"genpd_lock_nested", LOCK, 0},
442 {"genpd_lock_interruptible", LOCK, 0},
443 {"genpd_unlock", UNLOCK, 0},
446 static const char *false_positives[][2] = {
447 {"fs/jffs2/", "->alloc_sem"},
448 {"fs/xfs/", "->b_sema"},
449 {"mm/", "pvmw->ptl"},
452 static struct stree *start_states;
454 static struct tracker_list *locks;
456 static struct expression *ignored_reset;
457 static void reset(struct sm_state *sm, struct expression *mod_expr)
459 struct expression *faked;
461 if (mod_expr && mod_expr->type == EXPR_ASSIGNMENT &&
462 mod_expr->left == ignored_reset)
463 return;
464 faked = get_faked_expression();
465 if (faked && faked->type == EXPR_ASSIGNMENT &&
466 faked->left == ignored_reset)
467 return;
469 set_state(my_id, sm->name, sm->sym, &start_state);
472 static struct smatch_state *get_start_state(struct sm_state *sm)
474 struct smatch_state *orig;
476 if (!sm)
477 return NULL;
479 orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
480 if (orig)
481 return orig;
482 return NULL;
485 static struct expression *remove_spinlock_check(struct expression *expr)
487 if (expr->type != EXPR_CALL)
488 return expr;
489 if (expr->fn->type != EXPR_SYMBOL)
490 return expr;
491 if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
492 return expr;
493 expr = get_argument_from_call_expr(expr->args, 0);
494 return expr;
497 static struct expression *filter_kernel_args(struct expression *arg)
499 if (arg->type == EXPR_PREOP && arg->op == '&')
500 return strip_expr(arg->unop);
501 if (!is_pointer(arg))
502 return arg;
503 return deref_expression(strip_expr(arg));
506 static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
508 expr = remove_spinlock_check(expr);
509 expr = filter_kernel_args(expr);
510 return expr_to_str_sym(expr, sym);
513 static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
515 struct lock_info *lock = &lock_table[index];
516 struct expression *arg;
518 *sym = NULL;
519 if (lock->arg == RETURN_VAL) {
520 return expr_to_var_sym(strip_expr(expr->left), sym);
521 } else if (lock->arg == NO_ARG) {
522 return alloc_string(get_lock_name(lock->type));
523 } else {
524 arg = get_argument_from_call_expr(expr->args, lock->arg);
525 if (!arg)
526 return NULL;
527 return lock_to_name_sym(arg, sym);
531 static struct smatch_state *unmatched_state(struct sm_state *sm)
533 return &start_state;
536 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
538 if (is_impossible_path())
539 set_state(my_id, cur->name, cur->sym, &impossible);
542 static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
544 if (s1 == &impossible)
545 return s2;
546 if (s2 == &impossible)
547 return s1;
548 return &merged;
551 static struct smatch_state *action_to_state(enum action lock_unlock)
553 switch (lock_unlock) {
554 case LOCK:
555 return &locked;
556 case UNLOCK:
557 return &unlocked;
558 case RESTORE:
559 return &restore;
561 return NULL;
564 static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
566 struct sm_state *sm;
567 struct sm_state *match;
568 int cnt = 0;
569 int start_pos, state_len, key_len, chunks, i;
571 if (strncmp(key, "$->", 3) == 0)
572 key += 3;
574 key_len = strlen(key);
575 chunks = 0;
576 for (i = key_len - 1; i > 0; i--) {
577 if (key[i] == '>' || key[i] == '.')
578 chunks++;
579 if (chunks == 2) {
580 key += (i + 1);
581 key_len = strlen(key);
582 break;
586 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
587 if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
588 sm->state != &locked) ||
589 (lock_unlock == LOCK && sm->state != &unlocked))
590 continue;
591 state_len = strlen(sm->name);
592 if (state_len < key_len)
593 continue;
594 start_pos = state_len - key_len;
595 if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
596 strcmp(sm->name + start_pos, key) == 0) {
597 cnt++;
598 match = sm;
600 } END_FOR_EACH_SM(sm);
602 if (cnt == 1)
603 return match;
604 return NULL;
607 static void use_best_match(char *key, enum action lock_unlock)
609 struct sm_state *match;
611 match = get_best_match(key, lock_unlock);
612 if (match)
613 set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
614 else
615 set_state(my_id, key, NULL, action_to_state(lock_unlock));
618 static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
620 struct smatch_state *orig;
622 orig = get_state_stree(start_states, my_id, name, sym);
623 if (!orig)
624 set_state_stree(&start_states, my_id, name, sym, start);
625 else if (orig != start)
626 set_state_stree(&start_states, my_id, name, sym, &undefined);
629 static bool common_false_positive(const char *name)
631 const char *path, *lname;
632 int i, len_total, len_path, len_name, skip;
634 if (!get_filename())
635 return false;
637 len_total = strlen(name);
638 for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
639 path = false_positives[i][0];
640 lname = false_positives[i][1];
642 len_path = strlen(path);
643 len_name = strlen(lname);
645 if (len_name > len_total)
646 continue;
647 skip = len_total - len_name;
649 if (strncmp(get_filename(), path, len_path) == 0 &&
650 strcmp(name + skip, lname) == 0)
651 return true;
654 return false;
657 static bool sm_in_start_states(struct sm_state *sm)
659 if (!sm || !cur_func_sym)
660 return false;
661 if (sm->line == cur_func_sym->pos.line)
662 return true;
663 return false;
666 static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
668 struct sm_state *tmp;
670 if (!sm)
671 return;
673 FOR_EACH_PTR(sm->possible, tmp) {
674 if (tmp->state == state)
675 goto found;
676 } END_FOR_EACH_PTR(tmp);
678 return;
679 found:
680 // FIXME: called with read_lock held
681 // drivers/scsi/aic7xxx/aic7xxx_osm.c:1591 ahc_linux_isr() error: double locked 'flags' (orig line 1584)
682 if (strcmp(sm->name, "bottom_half") == 0)
683 return;
684 if (strstr(sm->name, "rcu"))
685 return;
686 if (common_false_positive(sm->name))
687 return;
689 // if (state == &locked && sm_in_start_states(tmp))
690 // sm_warning("called with lock held. '%s'", sm->name);
691 // else
692 // sm_msg("error: double %s '%s' (orig line %u)",
693 // state->name, sm->name, tmp->line);
696 static bool handle_macro_lock_unlock(void)
698 struct expression *expr, *arg;
699 struct macro_info *info;
700 struct sm_state *sm;
701 struct symbol *sym;
702 const char *macro;
703 char *name;
704 bool ret = false;
705 int i;
707 expr = last_ptr_list((struct ptr_list *)big_expression_stack);
708 while (expr && expr->type == EXPR_ASSIGNMENT)
709 expr = strip_expr(expr->right);
710 if (!expr || expr->type != EXPR_CALL)
711 return false;
713 macro = get_macro_name(expr->pos);
714 if (!macro)
715 return false;
717 for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
718 info = &macro_table[i];
720 if (strcmp(macro, info->macro) != 0)
721 continue;
722 arg = get_argument_from_call_expr(expr->args, info->param);
723 name = expr_to_str_sym(arg, &sym);
724 if (!name || !sym)
725 goto free;
726 sm = get_sm_state(my_id, name, sym);
728 if (info->action == LOCK) {
729 if (!get_start_state(sm))
730 set_start_state(name, sym, &unlocked);
731 if (sm && sm->line != expr->pos.line)
732 warn_on_double(sm, &locked);
733 set_state(my_id, name, sym, &locked);
734 } else {
735 if (!get_start_state(sm))
736 set_start_state(name, sym, &locked);
737 if (sm && sm->line != expr->pos.line)
738 warn_on_double(sm, &unlocked);
739 set_state(my_id, name, sym, &unlocked);
741 ret = true;
742 free:
743 free_string(name);
744 return ret;
746 return false;
749 static bool is_local_IRQ_save(const char *name, struct symbol *sym, struct lock_info *info)
751 if (name && strcmp(name, "flags") == 0)
752 return true;
753 if (!sym)
754 return false;
755 if (!sym->ident || strcmp(sym->ident->name, name) != 0)
756 return false;
757 if (!info)
758 return false;
759 return strstr(info->function, "irq") && strstr(info->function, "save");
762 static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
764 struct sm_state *sm;
765 bool delete_null = false;
767 if (handle_macro_lock_unlock())
768 return;
770 add_tracker(&locks, my_id, name, sym);
772 sm = get_sm_state(my_id, name, sym);
773 if (!get_start_state(sm))
774 set_start_state(name, sym, &unlocked);
775 if (!sm && !is_local_IRQ_save(name, sym, info) && sym) {
776 sm = get_sm_state(my_id, name, NULL);
777 if (sm)
778 delete_null = true;
780 warn_on_double(sm, &locked);
781 if (delete_null)
782 delete_state(my_id, name, NULL);
783 delete_state(my_id, name, NULL);
785 set_state(my_id, name, sym, &locked);
788 static void do_lock_failed(const char *name, struct symbol *sym, struct lock_info *info)
790 add_tracker(&locks, my_id, name, sym);
791 if (!is_local_IRQ_save(name, sym, info) && sym)
792 delete_state(my_id, name, NULL);
793 set_state(my_id, name, sym, &unlocked);
796 static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
798 struct sm_state *sm;
799 bool delete_null = false;
801 if (__path_is_null())
802 return;
804 if (handle_macro_lock_unlock())
805 return;
807 add_tracker(&locks, my_id, name, sym);
808 sm = get_sm_state(my_id, name, sym);
809 if (!sm && !is_local_IRQ_save(name, sym, info)) {
810 sm = get_best_match(name, UNLOCK);
811 if (sm) {
812 name = sm->name;
813 if (sm->sym)
814 sym = sm->sym;
815 else
816 delete_null = true;
819 if (!get_start_state(sm))
820 set_start_state(name, sym, &locked);
821 warn_on_double(sm, &unlocked);
822 if (delete_null)
823 delete_state(my_id, name, NULL);
824 set_state(my_id, name, sym, &unlocked);
827 static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
829 struct sm_state *sm;
831 if (__path_is_null())
832 return;
834 sm = get_sm_state(my_id, name, sym);
835 if (!get_start_state(sm))
836 set_start_state(name, sym, &locked);
838 add_tracker(&locks, my_id, name, sym);
839 set_state(my_id, name, sym, &restore);
842 static void match_lock_held(const char *fn, struct expression *call_expr,
843 struct expression *assign_expr, void *_index)
845 int index = PTR_INT(_index);
846 struct lock_info *lock = &lock_table[index];
847 char *lock_name;
848 struct symbol *sym;
850 if (lock->arg == NO_ARG) {
851 lock_name = get_full_name(NULL, index, &sym);
852 } else if (lock->arg == RETURN_VAL) {
853 if (!assign_expr)
854 return;
855 lock_name = get_full_name(assign_expr, index, &sym);
856 } else {
857 lock_name = get_full_name(call_expr, index, &sym);
859 if (!lock_name)
860 return;
861 do_lock(lock_name, sym, lock);
862 free_string(lock_name);
865 static void match_lock_failed(const char *fn, struct expression *call_expr,
866 struct expression *assign_expr, void *_index)
868 int index = PTR_INT(_index);
869 struct lock_info *lock = &lock_table[index];
870 char *lock_name;
871 struct symbol *sym;
873 if (lock->arg == NO_ARG) {
874 lock_name = get_full_name(NULL, index, &sym);
875 } else if (lock->arg == RETURN_VAL) {
876 if (!assign_expr)
877 return;
878 lock_name = get_full_name(assign_expr, index, &sym);
879 } else {
880 lock_name = get_full_name(call_expr, index, &sym);
882 if (!lock_name)
883 return;
884 do_lock_failed(lock_name, sym, lock);
885 free_string(lock_name);
888 static void match_returns_locked(const char *fn, struct expression *expr,
889 void *_index)
891 int index = PTR_INT(_index);
892 struct lock_info *lock = &lock_table[index];
893 char *full_name;
894 struct symbol *sym;
896 if (lock->arg != RETURN_VAL)
897 return;
898 full_name = get_full_name(expr, index, &sym);
899 if (!full_name)
900 return;
901 do_lock(full_name, sym, lock);
904 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
906 int index = PTR_INT(_index);
907 struct lock_info *lock = &lock_table[index];
908 char *full_name;
909 struct symbol *sym;
911 full_name = get_full_name(expr, index, &sym);
912 if (!full_name)
913 return;
914 switch (lock->action) {
915 case LOCK:
916 do_lock(full_name, sym, lock);
917 break;
918 case UNLOCK:
919 do_unlock(full_name, sym, lock);
920 break;
921 case RESTORE:
922 do_restore(full_name, sym, lock);
923 break;
925 free_string(full_name);
928 static int get_db_type(struct sm_state *sm)
931 * Bottom half is complicated because it's nestable.
932 * Say it's merged at the start and we lock and unlock then
933 * it should go back to merged.
935 if (sm->state == get_start_state(sm)) {
936 if (sm->state == &locked)
937 return KNOWN_LOCKED;
938 if (sm->state == &unlocked)
939 return KNOWN_UNLOCKED;
942 if (sm->state == &locked)
943 return LOCKED;
944 if (sm->state == &unlocked)
945 return UNLOCKED;
946 if (sm->state == &restore)
947 return LOCK_RESTORED;
948 return LOCKED;
951 static struct stree *already_done;
952 static void save_recorded_state(int return_id, int param, const char *param_name,
953 struct smatch_state *state)
955 /* using the sym like this is an ugly hack */
956 set_state_stree(&already_done, my_id, param_name,
957 (struct symbol *)(unsigned long)((return_id << 8) | param),
958 state);
961 static struct smatch_state *get_recorded_state(int return_id, int param, const char *param_name)
963 return get_state_stree(already_done, my_id, param_name,
964 (struct symbol *)(unsigned long)((return_id << 8) | param));
967 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
969 struct smatch_state *start, *recorded;
970 struct sm_state *sm;
971 const char *param_name;
972 int param;
974 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
975 if (sm->state != &locked &&
976 sm->state != &unlocked &&
977 sm->state != &restore)
978 continue;
979 if (sm->name[0] == '$')
980 continue;
983 * If the state is locked at the end, that doesn't mean
984 * anything. It could be been locked at the start. Or
985 * it could be &merged at the start but its locked now
986 * because of implications and not because we set the
987 * state.
989 * This is slightly a hack, but when we change the state, we
990 * call set_start_state() so if get_start_state() returns NULL
991 * that means we haven't manually the locked state.
993 start = get_start_state(sm);
994 if (sm->state == &restore) {
995 if (start != &locked)
996 continue;
997 } else if (!start || sm->state == start)
998 continue; /* !start means it was passed in */
1000 param = get_param_key_from_sm(sm, expr, &param_name);
1001 recorded = get_recorded_state(return_id, param, param_name);
1002 if (recorded && recorded == sm->state)
1003 continue;
1004 save_recorded_state(return_id, param, param_name, sm->state);
1005 sql_insert_return_states(return_id, return_ranges,
1006 get_db_type(sm),
1007 param, param_name, "");
1008 } END_FOR_EACH_SM(sm);
1011 enum {
1012 ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
1015 static bool is_EINTR(struct range_list *rl)
1017 sval_t sval;
1019 if (!rl_to_sval(rl, &sval))
1020 return false;
1021 return sval.value == -4;
1024 static int success_fail_positive(struct range_list *rl)
1026 /* void returns are the same as success (zero in the kernel) */
1027 if (!rl)
1028 return ZERO;
1030 if (rl_type(rl)->type != SYM_PTR &&
1031 !is_whole_rl(rl) &&
1032 sval_is_negative(rl_min(rl)))
1033 return NEGATIVE;
1035 if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
1036 return ZERO;
1038 if (is_err_ptr(rl_min(rl)) &&
1039 is_err_ptr(rl_max(rl)))
1040 return ERR_PTR;
1043 * Trying to match ERR_PTR(ret) but without the expression struct.
1044 * Ugly...
1046 if (type_bits(&long_ctype) == 64 &&
1047 rl_type(rl)->type == SYM_PTR &&
1048 rl_min(rl).value == INT_MIN)
1049 return ERR_PTR;
1051 return POSITIVE;
1054 static bool sym_in_lock_table(struct symbol *sym)
1056 int i;
1058 if (!sym || !sym->ident)
1059 return false;
1061 for (i = 0; lock_table[i].function != NULL; i++) {
1062 if (strcmp(lock_table[i].function, sym->ident->name) == 0)
1063 return true;
1065 return false;
1068 static bool func_in_lock_table(struct expression *expr)
1070 if (expr->type != EXPR_SYMBOL)
1071 return false;
1072 return sym_in_lock_table(expr->symbol);
1075 static void check_lock(char *name, struct symbol *sym)
1077 struct range_list *locked_lines = NULL;
1078 struct range_list *unlocked_lines = NULL;
1079 int locked_buckets[NUM_BUCKETS] = {};
1080 int unlocked_buckets[NUM_BUCKETS] = {};
1081 struct stree *stree, *orig;
1082 struct sm_state *return_sm;
1083 struct sm_state *sm;
1084 sval_t line = sval_type_val(&int_ctype, 0);
1085 int bucket;
1086 int i;
1088 if (sym_in_lock_table(cur_func_sym))
1089 return;
1091 FOR_EACH_PTR(get_all_return_strees(), stree) {
1092 orig = __swap_cur_stree(stree);
1094 if (is_impossible_path())
1095 goto swap_stree;
1097 return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
1098 if (!return_sm)
1099 goto swap_stree;
1100 line.value = return_sm->line;
1102 sm = get_sm_state(my_id, name, sym);
1103 if (!sm)
1104 goto swap_stree;
1106 if (parent_is_gone_var_sym(sm->name, sm->sym))
1107 goto swap_stree;
1109 if (sm->state != &locked &&
1110 sm->state != &unlocked &&
1111 sm->state != &restore)
1112 goto swap_stree;
1114 if ((sm->state == &unlocked || sm->state == &restore) &&
1115 is_EINTR(estate_rl(return_sm->state)))
1116 goto swap_stree;
1118 bucket = success_fail_positive(estate_rl(return_sm->state));
1119 if (sm->state == &locked) {
1120 add_range(&locked_lines, line, line);
1121 locked_buckets[bucket] = true;
1123 if (sm->state == &unlocked || sm->state == &restore) {
1124 add_range(&unlocked_lines, line, line);
1125 unlocked_buckets[bucket] = true;
1127 swap_stree:
1128 __swap_cur_stree(orig);
1129 } END_FOR_EACH_PTR(stree);
1132 if (!locked_lines || !unlocked_lines)
1133 return;
1135 for (i = 0; i < NUM_BUCKETS; i++) {
1136 if (locked_buckets[i] && unlocked_buckets[i])
1137 goto complain;
1139 if (locked_buckets[NEGATIVE] &&
1140 (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
1141 goto complain;
1143 if (locked_buckets[ERR_PTR])
1144 goto complain;
1146 return;
1148 complain:
1149 sm_msg("warn: inconsistent returns '%s'.", name);
1150 sm_printf(" Locked on : %s\n", show_rl(locked_lines));
1151 sm_printf(" Unlocked on: %s\n", show_rl(unlocked_lines));
1154 static void match_func_end(struct symbol *sym)
1156 struct tracker *tracker;
1158 FOR_EACH_PTR(locks, tracker) {
1159 check_lock(tracker->name, tracker->sym);
1160 } END_FOR_EACH_PTR(tracker);
1163 static void register_lock(int index)
1165 struct lock_info *lock = &lock_table[index];
1166 void *idx = INT_PTR(index);
1168 if (lock->return_type == ret_one) {
1169 return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
1170 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
1171 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
1172 add_function_assign_hook(lock->function, &match_returns_locked, idx);
1173 } else if (lock->return_type == ret_any) {
1174 add_function_hook(lock->function, &match_lock_unlock, idx);
1175 } else if (lock->return_type == ret_zero) {
1176 return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
1177 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
1178 } else if (lock->return_type == ret_valid_ptr) {
1179 return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
1183 static void load_table(struct lock_info *lock_table)
1185 int i;
1187 for (i = 0; lock_table[i].function != NULL; i++) {
1188 if (lock_table[i].action == LOCK)
1189 register_lock(i);
1190 else
1191 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
1195 static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
1197 struct expression *call, *arg;
1198 char *name;
1199 struct symbol *sym;
1201 call = expr;
1202 while (call->type == EXPR_ASSIGNMENT)
1203 call = strip_expr(call->right);
1204 if (call->type != EXPR_CALL)
1205 return;
1207 if (func_in_lock_table(call->fn))
1208 return;
1210 if (param == -2) {
1211 use_best_match(key, lock_unlock);
1212 return;
1215 if (param == -1) {
1216 if (expr->type != EXPR_ASSIGNMENT)
1217 return;
1218 ignored_reset = expr->left;
1219 name = get_variable_from_key(expr->left, key, &sym);
1220 } else {
1221 arg = get_argument_from_call_expr(call->args, param);
1222 if (!arg)
1223 return;
1225 name = get_variable_from_key(arg, key, &sym);
1227 if (!name || !sym)
1228 goto free;
1230 if (lock_unlock == LOCK)
1231 do_lock(name, sym, NULL);
1232 else if (lock_unlock == UNLOCK)
1233 do_unlock(name, sym, NULL);
1234 else if (lock_unlock == RESTORE)
1235 do_restore(name, sym, NULL);
1237 free:
1238 free_string(name);
1241 static void db_param_locked(struct expression *expr, int param, char *key, char *value)
1243 db_param_locked_unlocked(expr, param, key, value, LOCK);
1246 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
1248 db_param_locked_unlocked(expr, param, key, value, UNLOCK);
1251 static void db_param_restore(struct expression *expr, int param, char *key, char *value)
1253 db_param_locked_unlocked(expr, param, key, value, RESTORE);
1256 static void match_assign(struct expression *expr)
1258 struct smatch_state *state;
1260 /* This is only for the DB */
1261 if (!__in_fake_var_assign)
1262 return;
1263 state = get_state_expr(my_id, expr->right);
1264 if (!state)
1265 return;
1266 set_state_expr(my_id, expr->left, state);
1269 static struct stree *printed;
1270 static void call_info_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
1272 int locked_type = 0;
1274 if (sm->state == &locked)
1275 locked_type = LOCKED;
1276 else if (sm->state == &unlocked)
1277 locked_type = UNLOCKED;
1278 else if (slist_has_state(sm->possible, &locked) ||
1279 slist_has_state(sm->possible, &half_locked))
1280 locked_type = HALF_LOCKED;
1281 else
1282 return;
1284 avl_insert(&printed, sm);
1285 sql_insert_caller_info(call, locked_type, param, printed_name, "");
1288 static void match_call_info(struct expression *expr)
1290 struct sm_state *sm;
1291 const char *name;
1292 int locked_type;
1294 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
1295 if (sm->state == &locked)
1296 locked_type = LOCKED;
1297 else if (sm->state == &half_locked ||
1298 slist_has_state(sm->possible, &locked))
1299 locked_type = HALF_LOCKED;
1300 else
1301 continue;
1303 if (avl_lookup(printed, sm))
1304 continue;
1306 if (strcmp(sm->name, "bottom_half") == 0)
1307 name = "bh";
1308 else if (strcmp(sm->name, "rcu_read") == 0)
1309 name = "rcu_read_lock";
1310 else
1311 name = sm->name;
1313 sql_insert_caller_info(expr, locked_type, -2, name, "");
1314 } END_FOR_EACH_SM(sm);
1315 free_stree(&printed);
1318 static void set_locked_called_state(const char *name, struct symbol *sym,
1319 char *key, char *value,
1320 struct smatch_state *state)
1322 char fullname[256];
1324 if (name && key[0] == '$')
1325 snprintf(fullname, sizeof(fullname), "%s%s", name, key + 1);
1326 else
1327 snprintf(fullname, sizeof(fullname), "%s", key);
1329 if (strstr(fullname, ">>") || strstr(fullname, "..")) {
1330 // sm_msg("warn: invalid lock name. name = '%s' key = '%s'", name, key);
1331 return;
1334 set_state(my_id, fullname, sym, state);
1337 static void set_locked(const char *name, struct symbol *sym, char *key, char *value)
1339 set_locked_called_state(name, sym, key, value, &locked);
1342 static void set_half_locked(const char *name, struct symbol *sym, char *key, char *value)
1344 set_locked_called_state(name, sym, key, value, &half_locked);
1347 static void set_unlocked(const char *name, struct symbol *sym, char *key, char *value)
1349 set_locked_called_state(name, sym, key, value, &unlocked);
1352 static void match_after_func(struct symbol *sym)
1354 free_stree(&start_states);
1355 free_stree(&already_done);
1358 static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
1359 struct expression *assign_expr, void *_index)
1361 struct expression *lock, *ctx;
1362 char *lock_name;
1363 struct symbol *sym;
1365 lock = get_argument_from_call_expr(call_expr->args, 0);
1366 ctx = get_argument_from_call_expr(call_expr->args, 1);
1367 if (!expr_is_zero(ctx))
1368 return;
1370 lock_name = lock_to_name_sym(lock, &sym);
1371 if (!lock_name || !sym)
1372 goto free;
1373 do_lock(lock_name, sym, NULL);
1374 free:
1375 free_string(lock_name);
1378 /* print_held_locks() is used in check_call_tree.c */
1379 void print_held_locks(void)
1381 struct stree *stree;
1382 struct sm_state *sm;
1383 int i = 0;
1385 stree = __get_cur_stree();
1386 FOR_EACH_MY_SM(my_id, stree, sm) {
1387 if (sm->state != &locked)
1388 continue;
1389 if (i++)
1390 sm_printf(" ");
1391 sm_printf("'%s'", sm->name);
1392 } END_FOR_EACH_SM(sm);
1395 static bool is_smp_config(void)
1397 struct ident *id;
1399 id = built_in_ident("CONFIG_SMP");
1400 return !!lookup_symbol(id, NS_MACRO);
1403 void check_locking(int id)
1405 my_id = id;
1407 if (option_project != PROJ_KERNEL)
1408 return;
1410 if (!is_smp_config())
1411 return;
1413 load_table(lock_table);
1415 set_dynamic_states(my_id);
1416 add_unmatched_state_hook(my_id, &unmatched_state);
1417 add_pre_merge_hook(my_id, &pre_merge_hook);
1418 add_merge_hook(my_id, &merge_func);
1419 add_modification_hook(my_id, &reset);
1421 add_hook(&match_assign, ASSIGNMENT_HOOK);
1422 add_hook(&match_func_end, END_FUNC_HOOK);
1424 add_hook(&match_after_func, AFTER_FUNC_HOOK);
1425 add_function_data((unsigned long *)&start_states);
1427 add_caller_info_callback(my_id, call_info_callback);
1428 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
1430 add_split_return_callback(match_return_info);
1431 select_return_states_hook(LOCKED, &db_param_locked);
1432 select_return_states_hook(UNLOCKED, &db_param_unlocked);
1433 select_return_states_hook(LOCK_RESTORED, &db_param_restore);
1435 select_caller_info_hook(set_locked, LOCKED);
1436 select_caller_info_hook(set_half_locked, HALF_LOCKED);
1437 select_caller_info_hook(set_unlocked, UNLOCKED);
1439 return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);