xref: /illumos-gate/usr/src/tools/smatch/src/check_locking.c (revision 31ad075e90bf5afda8ab4b8cc4d3ca3e89946115)
1 /*
2  * Copyright (C) 2009 Dan Carpenter.
3  * Copyright (C) 2019 Oracle.
4  *
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.
9  *
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.
14  *
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
17  */
18 
19 #include <ctype.h>
20 #include "parse.h"
21 #include "smatch.h"
22 #include "smatch_extra.h"
23 #include "smatch_slist.h"
24 
25 static int my_id;
26 
27 STATE(locked);
28 STATE(half_locked);
29 STATE(start_state);
30 STATE(unlocked);
31 STATE(impossible);
32 STATE(restore);
33 
34 enum action {
35 	LOCK,
36 	UNLOCK,
37 	RESTORE,
38 };
39 
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 };
51 
get_lock_name(enum lock_type type)52 const char *get_lock_name(enum lock_type type)
53 {
54 	static const char *names[] = {
55 		[spin_lock] = "spin_lock",
56 		[read_lock] = "read_lock",
57 		[write_lock] = "write_lock",
58 		[mutex] = "mutex",
59 		[bottom_half] = "bottom_half",
60 		[irq] = "irq",
61 		[sem] = "sem",
62 		[prepare_lock] = "prepare_lock",
63 		[enable_lock] = "enable_lock",
64 	};
65 
66 	return names[type];
67 }
68 
69 enum return_type {
70 	ret_any,
71 	ret_zero,
72 	ret_one,
73 	ret_negative,
74 	ret_positive,
75 	ret_valid_ptr,
76 };
77 
78 #define RETURN_VAL -1
79 #define NO_ARG -2
80 
81 struct lock_info {
82 	const char *function;
83 	enum action action;
84 	enum lock_type type;
85 	int arg;
86 	enum return_type return_type;
87 };
88 
89 static struct lock_info lock_table[] = {
90 	{"spin_lock",                  LOCK,   spin_lock, 0, ret_any},
91 	{"spin_unlock",                UNLOCK, spin_lock, 0, ret_any},
92 	{"spin_lock_nested",           LOCK,   spin_lock, 0, ret_any},
93 	{"_spin_lock",                 LOCK,   spin_lock, 0, ret_any},
94 	{"_spin_unlock",               UNLOCK, spin_lock, 0, ret_any},
95 	{"_spin_lock_nested",          LOCK,   spin_lock, 0, ret_any},
96 	{"__spin_lock",                LOCK,   spin_lock, 0, ret_any},
97 	{"__spin_unlock",              UNLOCK, spin_lock, 0, ret_any},
98 	{"__spin_lock_nested",         LOCK,   spin_lock, 0, ret_any},
99 	{"raw_spin_lock",              LOCK,   spin_lock, 0, ret_any},
100 	{"raw_spin_unlock",            UNLOCK, spin_lock, 0, ret_any},
101 	{"_raw_spin_lock",             LOCK,   spin_lock, 0, ret_any},
102 	{"_raw_spin_lock_nested",      LOCK,   spin_lock, 0, ret_any},
103 	{"_raw_spin_unlock",           UNLOCK, spin_lock, 0, ret_any},
104 	{"__raw_spin_lock",            LOCK,   spin_lock, 0, ret_any},
105 	{"__raw_spin_unlock",          UNLOCK, spin_lock, 0, ret_any},
106 
107 	{"spin_lock_irq",                 LOCK,   spin_lock, 0, ret_any},
108 	{"spin_unlock_irq",               UNLOCK, spin_lock, 0, ret_any},
109 	{"_spin_lock_irq",                LOCK,   spin_lock, 0, ret_any},
110 	{"_spin_unlock_irq",              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 	{"_raw_spin_lock_irq",            LOCK,   spin_lock, 0, ret_any},
114 	{"_raw_spin_unlock_irq",          UNLOCK, spin_lock, 0, ret_any},
115 	{"__raw_spin_unlock_irq",         UNLOCK, spin_lock, 0, ret_any},
116 	{"spin_lock_irqsave",             LOCK,   spin_lock, 0, ret_any},
117 	{"spin_unlock_irqrestore",        UNLOCK, spin_lock, 0, ret_any},
118 	{"_spin_lock_irqsave",            LOCK,   spin_lock, 0, ret_any},
119 	{"_spin_unlock_irqrestore",       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 	{"_raw_spin_lock_irqsave",        LOCK,   spin_lock, 0, ret_any},
123 	{"_raw_spin_unlock_irqrestore",   UNLOCK, spin_lock, 0, ret_any},
124 	{"__raw_spin_lock_irqsave",       LOCK,   spin_lock, 0, ret_any},
125 	{"__raw_spin_unlock_irqrestore",  UNLOCK, spin_lock, 0, ret_any},
126 	{"spin_lock_irqsave_nested",      LOCK,   spin_lock, 0, ret_any},
127 	{"_spin_lock_irqsave_nested",     LOCK,   spin_lock, 0, ret_any},
128 	{"__spin_lock_irqsave_nested",    LOCK,   spin_lock, 0, ret_any},
129 	{"_raw_spin_lock_irqsave_nested", LOCK,   spin_lock, 0, ret_any},
130 	{"spin_lock_bh",                  LOCK,   spin_lock, 0, ret_any},
131 	{"spin_unlock_bh",                UNLOCK, spin_lock, 0, ret_any},
132 	{"_spin_lock_bh",                 LOCK,   spin_lock, 0, ret_any},
133 	{"_spin_unlock_bh",               UNLOCK, 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 
137 	{"spin_trylock",               LOCK,   spin_lock, 0, ret_one},
138 	{"_spin_trylock",              LOCK,   spin_lock, 0, ret_one},
139 	{"__spin_trylock",             LOCK,   spin_lock, 0, ret_one},
140 	{"raw_spin_trylock",           LOCK,   spin_lock, 0, ret_one},
141 	{"_raw_spin_trylock",          LOCK,   spin_lock, 0, ret_one},
142 	{"spin_trylock_irq",           LOCK,   spin_lock, 0, ret_one},
143 	{"spin_trylock_irqsave",       LOCK,   spin_lock, 0, ret_one},
144 	{"spin_trylock_bh",            LOCK,   spin_lock, 0, ret_one},
145 	{"_spin_trylock_bh",           LOCK,   spin_lock, 0, ret_one},
146 	{"__spin_trylock_bh",          LOCK,   spin_lock, 0, ret_one},
147 	{"__raw_spin_trylock",         LOCK,   spin_lock, 0, ret_one},
148 	{"_atomic_dec_and_lock",       LOCK,   spin_lock, 1, ret_one},
149 
150 	{"read_lock",                 LOCK,   read_lock, 0, ret_any},
151 	{"down_read",                 LOCK,   read_lock, 0, ret_any},
152 	{"down_read_nested",          LOCK,   read_lock, 0, ret_any},
153 	{"down_read_trylock",         LOCK,   read_lock, 0, ret_one},
154 	{"up_read",                   UNLOCK, read_lock, 0, ret_any},
155 	{"read_unlock",               UNLOCK, read_lock, 0, ret_any},
156 	{"_read_lock",                LOCK,   read_lock, 0, ret_any},
157 	{"_read_unlock",              UNLOCK, read_lock, 0, ret_any},
158 	{"__read_lock",               LOCK,   read_lock, 0, ret_any},
159 	{"__read_unlock",             UNLOCK, read_lock, 0, ret_any},
160 	{"_raw_read_lock",            LOCK,   read_lock, 0, ret_any},
161 	{"_raw_read_unlock",          UNLOCK, read_lock, 0, ret_any},
162 	{"__raw_read_lock",           LOCK,   read_lock, 0, ret_any},
163 	{"__raw_read_unlock",         UNLOCK, read_lock, 0, ret_any},
164 	{"read_lock_irq",             LOCK,   read_lock, 0, ret_any},
165 	{"read_unlock_irq" ,          UNLOCK, read_lock, 0, ret_any},
166 	{"_read_lock_irq",            LOCK,   read_lock, 0, ret_any},
167 	{"_read_unlock_irq",          UNLOCK, read_lock, 0, ret_any},
168 	{"__read_lock_irq",           LOCK,   read_lock, 0, ret_any},
169 	{"__read_unlock_irq",         UNLOCK, read_lock, 0, ret_any},
170 	{"_raw_read_unlock_irq",      UNLOCK, read_lock, 0, ret_any},
171 	{"_raw_read_lock_irq",        LOCK,   read_lock, 0, ret_any},
172 	{"_raw_read_lock_bh",         LOCK,   read_lock, 0, ret_any},
173 	{"_raw_read_unlock_bh",       UNLOCK, read_lock, 0, ret_any},
174 	{"read_lock_irqsave",         LOCK,   read_lock, 0, ret_any},
175 	{"read_unlock_irqrestore",    UNLOCK, read_lock, 0, ret_any},
176 	{"_read_lock_irqsave",        LOCK,   read_lock, 0, ret_any},
177 	{"_read_unlock_irqrestore",   UNLOCK, read_lock, 0, ret_any},
178 	{"__read_lock_irqsave",       LOCK,   read_lock, 0, ret_any},
179 	{"__read_unlock_irqrestore",  UNLOCK, read_lock, 0, ret_any},
180 	{"read_lock_bh",              LOCK,   read_lock, 0, ret_any},
181 	{"read_unlock_bh",            UNLOCK, read_lock, 0, ret_any},
182 	{"_read_lock_bh",             LOCK,   read_lock, 0, ret_any},
183 	{"_read_unlock_bh",           UNLOCK, read_lock, 0, ret_any},
184 	{"__read_lock_bh",            LOCK,   read_lock, 0, ret_any},
185 	{"__read_unlock_bh",          UNLOCK, read_lock, 0, ret_any},
186 	{"__raw_read_lock_bh",        LOCK,   read_lock, 0, ret_any},
187 	{"__raw_read_unlock_bh",      UNLOCK, read_lock, 0, ret_any},
188 
189 	{"_raw_read_lock_irqsave",        LOCK,    read_lock,   0,          ret_any},
190 	{"_raw_read_lock_irqsave",        LOCK,    irq,	        RETURN_VAL, ret_any},
191 	{"_raw_read_unlock_irqrestore",   UNLOCK,  read_lock,   0,          ret_any},
192 	{"_raw_read_unlock_irqrestore",   RESTORE, irq,         1,          ret_any},
193 	{"_raw_spin_lock_bh",             LOCK,    read_lock,   0,          ret_any},
194 	{"_raw_spin_lock_bh",             LOCK,    bottom_half, NO_ARG,     ret_any},
195 	{"_raw_spin_lock_nest_lock",      LOCK,    read_lock,   0,          ret_any},
196 	{"_raw_spin_unlock_bh",           UNLOCK,  read_lock,   0,          ret_any},
197 	{"_raw_spin_unlock_bh",           UNLOCK,  bottom_half, NO_ARG,     ret_any},
198 	{"_raw_write_lock_irqsave",       LOCK,    write_lock,  0,          ret_any},
199 	{"_raw_write_lock_irqsave",       LOCK,    irq,         RETURN_VAL, ret_any},
200 	{"_raw_write_unlock_irqrestore",  UNLOCK,  write_lock,  0,          ret_any},
201 	{"_raw_write_unlock_irqrestore",  RESTORE, irq,         1,          ret_any},
202 	{"__raw_write_unlock_irqrestore", UNLOCK,  write_lock,  0,          ret_any},
203 	{"__raw_write_unlock_irqrestore", RESTORE, irq,         1,          ret_any},
204 
205 	{"generic__raw_read_trylock", LOCK,   read_lock, 0, ret_one},
206 	{"read_trylock",              LOCK,   read_lock, 0, ret_one},
207 	{"_read_trylock",             LOCK,   read_lock, 0, ret_one},
208 	{"raw_read_trylock",          LOCK,   read_lock, 0, ret_one},
209 	{"_raw_read_trylock",         LOCK,   read_lock, 0, ret_one},
210 	{"__raw_read_trylock",        LOCK,   read_lock, 0, ret_one},
211 	{"__read_trylock",            LOCK,   read_lock, 0, ret_one},
212 
213 	{"write_lock",                LOCK,   write_lock, 0, ret_any},
214 	{"down_write",                LOCK,   write_lock, 0, ret_any},
215 	{"down_write_nested",         LOCK,   write_lock, 0, ret_any},
216 	{"up_write",                  UNLOCK, write_lock, 0, ret_any},
217 	{"write_unlock",              UNLOCK, write_lock, 0, ret_any},
218 	{"_write_lock",               LOCK,   write_lock, 0, ret_any},
219 	{"_write_unlock",             UNLOCK, write_lock, 0, ret_any},
220 	{"__write_lock",              LOCK,   write_lock, 0, ret_any},
221 	{"__write_unlock",            UNLOCK, write_lock, 0, ret_any},
222 	{"write_lock_irq",            LOCK,   write_lock, 0, ret_any},
223 	{"write_unlock_irq",          UNLOCK, write_lock, 0, ret_any},
224 	{"_write_lock_irq",           LOCK,   write_lock, 0, ret_any},
225 	{"_write_unlock_irq",         UNLOCK, write_lock, 0, ret_any},
226 	{"__write_lock_irq",          LOCK,   write_lock, 0, ret_any},
227 	{"__write_unlock_irq",        UNLOCK, write_lock, 0, ret_any},
228 	{"_raw_write_unlock_irq",     UNLOCK, write_lock, 0, ret_any},
229 	{"write_lock_irqsave",        LOCK,   write_lock, 0, ret_any},
230 	{"write_unlock_irqrestore",   UNLOCK, write_lock, 0, ret_any},
231 	{"_write_lock_irqsave",       LOCK,   write_lock, 0, ret_any},
232 	{"_write_unlock_irqrestore",  UNLOCK, write_lock, 0, ret_any},
233 	{"__write_lock_irqsave",      LOCK,   write_lock, 0, ret_any},
234 	{"__write_unlock_irqrestore", UNLOCK, write_lock, 0, ret_any},
235 	{"write_lock_bh",             LOCK,   write_lock, 0, ret_any},
236 	{"write_unlock_bh",           UNLOCK, write_lock, 0, ret_any},
237 	{"_write_lock_bh",            LOCK,   write_lock, 0, ret_any},
238 	{"_write_unlock_bh",          UNLOCK, write_lock, 0, ret_any},
239 	{"__write_lock_bh",           LOCK,   write_lock, 0, ret_any},
240 	{"__write_unlock_bh",         UNLOCK, write_lock, 0, ret_any},
241 	{"_raw_write_lock",           LOCK,   write_lock, 0, ret_any},
242 	{"__raw_write_lock",          LOCK,   write_lock, 0, ret_any},
243 	{"_raw_write_unlock",         UNLOCK, write_lock, 0, ret_any},
244 	{"__raw_write_unlock",        UNLOCK, write_lock, 0, ret_any},
245 	{"_raw_write_lock_bh",        LOCK,   write_lock, 0, ret_any},
246 	{"_raw_write_unlock_bh",      UNLOCK, write_lock, 0, ret_any},
247 	{"_raw_write_lock_irq",       LOCK,   write_lock, 0, ret_any},
248 
249 	{"write_trylock",             LOCK,   write_lock, 0, ret_one},
250 	{"_write_trylock",            LOCK,   write_lock, 0, ret_one},
251 	{"raw_write_trylock",         LOCK,   write_lock, 0, ret_one},
252 	{"_raw_write_trylock",        LOCK,   write_lock, 0, ret_one},
253 	{"__write_trylock",           LOCK,   write_lock, 0, ret_one},
254 	{"__raw_write_trylock",       LOCK,   write_lock, 0, ret_one},
255 	{"down_write_trylock",        LOCK,   write_lock, 0, ret_one},
256 	{"down_write_killable",       LOCK,   write_lock, 0, ret_zero},
257 
258 	{"down",               LOCK,   sem, 0, ret_any},
259 	{"up",                 UNLOCK, sem, 0, ret_any},
260 	{"down_trylock",       LOCK,   sem, 0, ret_zero},
261 	{"down_timeout",       LOCK,   sem, 0, ret_zero},
262 	{"down_interruptible", LOCK,   sem, 0, ret_zero},
263 	{"down_killable",      LOCK,   sem, 0, ret_zero},
264 
265 
266 	{"mutex_lock",                      LOCK,   mutex, 0, ret_any},
267 	{"mutex_unlock",                    UNLOCK, mutex, 0, ret_any},
268 	{"mutex_lock_nested",               LOCK,   mutex, 0, ret_any},
269 	{"mutex_lock_io",                   LOCK,   mutex, 0, ret_any},
270 	{"mutex_lock_io_nested",            LOCK,   mutex, 0, ret_any},
271 
272 	{"mutex_lock_interruptible",        LOCK,   mutex, 0, ret_zero},
273 	{"mutex_lock_interruptible_nested", LOCK,   mutex, 0, ret_zero},
274 	{"mutex_lock_killable",             LOCK,   mutex, 0, ret_zero},
275 	{"mutex_lock_killable_nested",      LOCK,   mutex, 0, ret_zero},
276 
277 	{"mutex_trylock",                   LOCK,   mutex, 0, ret_one},
278 
279 	{"ww_mutex_lock",		LOCK,   mutex, 0, ret_any},
280 	{"__ww_mutex_lock",		LOCK,   mutex, 0, ret_any},
281 	{"ww_mutex_lock_interruptible",	LOCK,   mutex, 0, ret_zero},
282 	{"ww_mutex_unlock",		UNLOCK, mutex, 0, ret_any},
283 
284 	{"raw_local_irq_disable", LOCK,   irq, NO_ARG, ret_any},
285 	{"raw_local_irq_enable",  UNLOCK, irq, NO_ARG, ret_any},
286 	{"spin_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
287 	{"spin_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
288 	{"_spin_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
289 	{"_spin_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
290 	{"__spin_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
291 	{"__spin_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
292 	{"_raw_spin_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
293 	{"_raw_spin_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
294 	{"__raw_spin_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
295 	{"spin_trylock_irq",      LOCK,   irq, NO_ARG, ret_one},
296 	{"read_lock_irq",         LOCK,   irq, NO_ARG, ret_any},
297 	{"read_unlock_irq",       UNLOCK, irq, NO_ARG, ret_any},
298 	{"_read_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
299 	{"_read_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
300 	{"__read_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
301 	{"_raw_read_lock_irq",    LOCK,   irq, NO_ARG, ret_any},
302 	{"__read_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
303 	{"_raw_read_unlock_irq",  UNLOCK, irq, NO_ARG, ret_any},
304 	{"write_lock_irq",        LOCK,   irq, NO_ARG, ret_any},
305 	{"write_unlock_irq",      UNLOCK, irq, NO_ARG, ret_any},
306 	{"_write_lock_irq",       LOCK,   irq, NO_ARG, ret_any},
307 	{"_write_unlock_irq",     UNLOCK, irq, NO_ARG, ret_any},
308 	{"__write_lock_irq",      LOCK,   irq, NO_ARG, ret_any},
309 	{"__write_unlock_irq",    UNLOCK, irq, NO_ARG, ret_any},
310 	{"_raw_write_lock_irq",   LOCK,   irq, NO_ARG, ret_any},
311 	{"_raw_write_unlock_irq", UNLOCK, irq, NO_ARG, ret_any},
312 
313 	{"arch_local_irq_save",        LOCK,      irq, RETURN_VAL, ret_any},
314 	{"arch_local_irq_restore",     RESTORE,   irq, 0,	   ret_any},
315 	{"__raw_local_irq_save",       LOCK,      irq, RETURN_VAL, ret_any},
316 	{"raw_local_irq_restore",      RESTORE,   irq, 0,	   ret_any},
317 	{"spin_lock_irqsave_nested",   LOCK,      irq, RETURN_VAL, ret_any},
318 	{"spin_lock_irqsave",          LOCK,      irq, 1,	   ret_any},
319 	{"spin_unlock_irqrestore",     RESTORE,   irq, 1,	   ret_any},
320 	{"_spin_lock_irqsave_nested",  LOCK,      irq, RETURN_VAL, ret_any},
321 	{"_spin_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
322 	{"_spin_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
323 	{"_spin_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
324 	{"__spin_lock_irqsave_nested", LOCK,      irq, 1,	   ret_any},
325 	{"__spin_lock_irqsave",        LOCK,      irq, 1,	   ret_any},
326 	{"__spin_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
327 	{"_raw_spin_lock_irqsave",     LOCK,      irq, RETURN_VAL, ret_any},
328 	{"_raw_spin_lock_irqsave",     LOCK,      irq, 1,	   ret_any},
329 	{"_raw_spin_unlock_irqrestore", RESTORE,  irq, 1,	   ret_any},
330 	{"__raw_spin_lock_irqsave",    LOCK,      irq, RETURN_VAL, ret_any},
331 	{"__raw_spin_unlock_irqrestore", RESTORE, irq, 1,	   ret_any},
332 	{"_raw_spin_lock_irqsave_nested", LOCK,   irq, RETURN_VAL, ret_any},
333 	{"spin_trylock_irqsave",       LOCK,      irq, 1,	   ret_one},
334 	{"read_lock_irqsave",          LOCK,      irq, RETURN_VAL, ret_any},
335 	{"read_lock_irqsave",          LOCK,      irq, 1,	   ret_any},
336 	{"read_unlock_irqrestore",     RESTORE,   irq, 1,	   ret_any},
337 	{"_read_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
338 	{"_read_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
339 	{"_read_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
340 	{"__read_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
341 	{"__read_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
342 	{"write_lock_irqsave",         LOCK,      irq, RETURN_VAL, ret_any},
343 	{"write_lock_irqsave",         LOCK,      irq, 1,	   ret_any},
344 	{"write_unlock_irqrestore",    RESTORE,   irq, 1,	   ret_any},
345 	{"_write_lock_irqsave",        LOCK,      irq, RETURN_VAL, ret_any},
346 	{"_write_lock_irqsave",        LOCK,      irq, 1,	   ret_any},
347 	{"_write_unlock_irqrestore",   RESTORE,   irq, 1,	   ret_any},
348 	{"__write_lock_irqsave",       LOCK,      irq, RETURN_VAL, ret_any},
349 	{"__write_unlock_irqrestore",  RESTORE,   irq, 1,	   ret_any},
350 
351 	{"local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
352 	{"_local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
353 	{"__local_bh_disable",	LOCK,	bottom_half, NO_ARG, ret_any},
354 	{"local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
355 	{"_local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
356 	{"__local_bh_enable",	UNLOCK,	bottom_half, NO_ARG, ret_any},
357 	{"spin_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
358 	{"spin_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
359 	{"_spin_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
360 	{"_spin_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
361 	{"__spin_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
362 	{"__spin_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
363 	{"read_lock_bh",        LOCK,   bottom_half, NO_ARG, ret_any},
364 	{"read_unlock_bh",      UNLOCK, bottom_half, NO_ARG, ret_any},
365 	{"_read_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
366 	{"_read_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
367 	{"__read_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
368 	{"__read_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
369 	{"_raw_read_lock_bh",   LOCK,   bottom_half, NO_ARG, ret_any},
370 	{"_raw_read_unlock_bh", UNLOCK, bottom_half, NO_ARG, ret_any},
371 	{"write_lock_bh",       LOCK,   bottom_half, NO_ARG, ret_any},
372 	{"write_unlock_bh",     UNLOCK, bottom_half, NO_ARG, ret_any},
373 	{"_write_lock_bh",      LOCK,   bottom_half, NO_ARG, ret_any},
374 	{"_write_unlock_bh",    UNLOCK, bottom_half, NO_ARG, ret_any},
375 	{"__write_lock_bh",     LOCK,   bottom_half, NO_ARG, ret_any},
376 	{"__write_unlock_bh",   UNLOCK, bottom_half, NO_ARG, ret_any},
377 	{"_raw_write_lock_bh",  LOCK,   bottom_half, NO_ARG, ret_any},
378 	{"_raw_write_unlock_bh",UNLOCK, bottom_half, NO_ARG, ret_any},
379 	{"spin_trylock_bh",     LOCK,   bottom_half, NO_ARG, ret_one},
380 	{"_spin_trylock_bh",    LOCK,   bottom_half, NO_ARG, ret_one},
381 	{"__spin_trylock_bh",   LOCK,   bottom_half, NO_ARG, ret_one},
382 
383 	{"ffs_mutex_lock",      LOCK,   mutex, 0, ret_zero},
384 
385 	{"clk_prepare_lock",    LOCK,   prepare_lock, NO_ARG, ret_any},
386 	{"clk_prepare_unlock",  UNLOCK, prepare_lock, NO_ARG, ret_any},
387 	{"clk_enable_lock",     LOCK,   enable_lock, -1, ret_any},
388 	{"clk_enable_unlock",   UNLOCK, enable_lock,  0, ret_any},
389 
390 	{"dma_resv_lock",	        LOCK,   mutex, 0, ret_zero},
391 	{"dma_resv_trylock",	        LOCK,	mutex, 0, ret_one},
392 	{"dma_resv_lock_interruptible", LOCK,	mutex, 0, ret_zero},
393 	{"dma_resv_unlock",		UNLOCK, mutex, 0, ret_any},
394 
395 	{"modeset_lock",			  LOCK,   mutex, 0, ret_zero},
396 	{"drm_ modeset_lock",			  LOCK,   mutex, 0, ret_zero},
397 	{"drm_modeset_lock_single_interruptible", LOCK,   mutex, 0, ret_zero},
398 	{"modeset_unlock",			  UNLOCK, mutex, 0, ret_any},
399 
400 	{"reiserfs_write_lock_nested",	 LOCK,   mutex, 0, ret_any},
401 	{"reiserfs_write_unlock_nested", UNLOCK, mutex, 0, ret_any},
402 
403 	{"rw_lock",                LOCK,   write_lock, 1, ret_any},
404 	{"rw_unlock",              UNLOCK, write_lock, 1, ret_any},
405 
406 	{"sem_lock",               LOCK,   mutex, 0, ret_any},
407 	{"sem_unlock",             UNLOCK, mutex, 0, ret_any},
408 
409 	{},
410 };
411 
412 struct macro_info {
413 	const char *macro;
414 	enum action action;
415 	int param;
416 };
417 
418 static struct macro_info macro_table[] = {
419 	{"genpd_lock",               LOCK,   0},
420 	{"genpd_lock_nested",        LOCK,   0},
421 	{"genpd_lock_interruptible", LOCK,   0},
422 	{"genpd_unlock",             UNLOCK, 0},
423 };
424 
425 static const char *false_positives[][2] = {
426 	{"fs/jffs2/", "->alloc_sem"},
427 	{"fs/xfs/", "->b_sema"},
428 	{"mm/", "pvmw->ptl"},
429 };
430 
431 static struct stree *start_states;
432 static struct stree_stack *saved_stack;
433 
434 static struct tracker_list *locks;
435 
reset(struct sm_state * sm,struct expression * mod_expr)436 static void reset(struct sm_state *sm, struct expression *mod_expr)
437 {
438 	set_state(my_id, sm->name, sm->sym, &start_state);
439 }
440 
remove_spinlock_check(struct expression * expr)441 static struct expression *remove_spinlock_check(struct expression *expr)
442 {
443 	if (expr->type != EXPR_CALL)
444 		return expr;
445 	if (expr->fn->type != EXPR_SYMBOL)
446 		return expr;
447 	if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
448 		return expr;
449 	expr = get_argument_from_call_expr(expr->args, 0);
450 	return expr;
451 }
452 
filter_kernel_args(struct expression * arg)453 static struct expression *filter_kernel_args(struct expression *arg)
454 {
455 	if (arg->type == EXPR_PREOP && arg->op == '&')
456 		return strip_expr(arg->unop);
457 	if (!is_pointer(arg))
458 		return arg;
459 	return deref_expression(strip_expr(arg));
460 }
461 
lock_to_name_sym(struct expression * expr,struct symbol ** sym)462 static char *lock_to_name_sym(struct expression *expr, struct symbol **sym)
463 {
464 	expr = remove_spinlock_check(expr);
465 	expr = filter_kernel_args(expr);
466 	return expr_to_str_sym(expr, sym);
467 }
468 
get_full_name(struct expression * expr,int index,struct symbol ** sym)469 static char *get_full_name(struct expression *expr, int index, struct symbol **sym)
470 {
471 	struct lock_info *lock = &lock_table[index];
472 	struct expression *arg;
473 
474 	*sym = NULL;
475 	if (lock->arg == RETURN_VAL) {
476 		return expr_to_var_sym(strip_expr(expr->left), sym);
477 	} else if (lock->arg == NO_ARG) {
478 		return alloc_string(get_lock_name(lock->type));
479 	} else {
480 		arg = get_argument_from_call_expr(expr->args, lock->arg);
481 		if (!arg)
482 			return NULL;
483 		return lock_to_name_sym(arg, sym);
484 	}
485 }
486 
unmatched_state(struct sm_state * sm)487 static struct smatch_state *unmatched_state(struct sm_state *sm)
488 {
489 	return &start_state;
490 }
491 
pre_merge_hook(struct sm_state * cur,struct sm_state * other)492 static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
493 {
494 	if (is_impossible_path())
495 		set_state(my_id, cur->name, cur->sym, &impossible);
496 }
497 
merge_func(struct smatch_state * s1,struct smatch_state * s2)498 static struct smatch_state *merge_func(struct smatch_state *s1, struct smatch_state *s2)
499 {
500 	if (s1 == &impossible)
501 		return s2;
502 	if (s2 == &impossible)
503 		return s1;
504 	return &merged;
505 }
506 
action_to_state(enum action lock_unlock)507 static struct smatch_state *action_to_state(enum action lock_unlock)
508 {
509 	switch (lock_unlock) {
510 	case LOCK:
511 		return &locked;
512 	case UNLOCK:
513 		return &unlocked;
514 	case RESTORE:
515 		return &restore;
516 	}
517 	return NULL;
518 }
519 
get_best_match(const char * key,enum action lock_unlock)520 static struct sm_state *get_best_match(const char *key, enum action lock_unlock)
521 {
522 	struct sm_state *sm;
523 	struct sm_state *match;
524 	int cnt = 0;
525 	int start_pos, state_len, key_len, chunks, i;
526 
527 	if (strncmp(key, "$->", 3) == 0)
528 		key += 3;
529 
530 	key_len = strlen(key);
531 	chunks = 0;
532 	for (i = key_len - 1; i > 0; i--) {
533 		if (key[i] == '>' || key[i] == '.')
534 			chunks++;
535 		if (chunks == 2) {
536 			key += (i + 1);
537 			key_len = strlen(key);
538 			break;
539 		}
540 	}
541 
542 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
543 		if (((lock_unlock == UNLOCK || lock_unlock == RESTORE) &&
544 		     sm->state != &locked) ||
545 		    (lock_unlock == LOCK && sm->state != &unlocked))
546 			continue;
547 		state_len = strlen(sm->name);
548 		if (state_len < key_len)
549 			continue;
550 		start_pos = state_len - key_len;
551 		if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
552 		    strcmp(sm->name + start_pos, key) == 0) {
553 			cnt++;
554 			match = sm;
555 		}
556 	} END_FOR_EACH_SM(sm);
557 
558 	if (cnt == 1)
559 		return match;
560 	return NULL;
561 }
562 
use_best_match(char * key,enum action lock_unlock)563 static void use_best_match(char *key, enum action lock_unlock)
564 {
565 	struct sm_state *match;
566 
567 	match = get_best_match(key, lock_unlock);
568 	if (match)
569 		set_state(my_id, match->name, match->sym, action_to_state(lock_unlock));
570 	else
571 		set_state(my_id, key, NULL, action_to_state(lock_unlock));
572 }
573 
set_start_state(const char * name,struct symbol * sym,struct smatch_state * start)574 static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
575 {
576 	struct smatch_state *orig;
577 
578 	orig = get_state_stree(start_states, my_id, name, sym);
579 	if (!orig)
580 		set_state_stree(&start_states, my_id, name, sym, start);
581 	else if (orig != start)
582 		set_state_stree(&start_states, my_id, name, sym, &undefined);
583 }
584 
common_false_positive(const char * name)585 static bool common_false_positive(const char *name)
586 {
587 	const char *path, *lname;
588 	int i, len_total, len_path, len_name, skip;
589 
590 	if (!get_filename())
591 		return false;
592 
593 	len_total = strlen(name);
594 	for (i = 0; i < ARRAY_SIZE(false_positives); i++) {
595 		path = false_positives[i][0];
596 		lname = false_positives[i][1];
597 
598 		len_path = strlen(path);
599 		len_name = strlen(lname);
600 
601 		if (len_name > len_total)
602 			continue;
603 		skip = len_total - len_name;
604 
605 		if (strncmp(get_filename(), path, len_path) == 0 &&
606 		    strcmp(name + skip, lname) == 0)
607 			return true;
608 	}
609 
610 	return false;
611 }
612 
warn_on_double(struct sm_state * sm,struct smatch_state * state)613 static void warn_on_double(struct sm_state *sm, struct smatch_state *state)
614 {
615 	struct sm_state *tmp;
616 
617 	if (!sm)
618 		return;
619 
620 	FOR_EACH_PTR(sm->possible, tmp) {
621 		if (tmp->state == state)
622 			goto found;
623 	} END_FOR_EACH_PTR(tmp);
624 
625 	return;
626 found:
627 	if (strcmp(sm->name, "bottom_half") == 0)
628 		return;
629 	if (common_false_positive(sm->name))
630 		return;
631 	sm_msg("error: double %s '%s' (orig line %u)",
632 	       state->name, sm->name, tmp->line);
633 }
634 
handle_macro_lock_unlock(void)635 static bool handle_macro_lock_unlock(void)
636 {
637 	struct expression *expr, *arg;
638 	struct macro_info *info;
639 	struct sm_state *sm;
640 	struct symbol *sym;
641 	const char *macro;
642 	char *name;
643 	bool ret = false;
644 	int i;
645 
646 	expr = last_ptr_list((struct ptr_list *)big_expression_stack);
647 	while (expr && expr->type == EXPR_ASSIGNMENT)
648 		expr = strip_expr(expr->right);
649 	if (!expr || expr->type != EXPR_CALL)
650 		return false;
651 
652 	macro = get_macro_name(expr->pos);
653 	if (!macro)
654 		return false;
655 
656 	for (i = 0; i < ARRAY_SIZE(macro_table); i++) {
657 		info = &macro_table[i];
658 
659 		if (strcmp(macro, info->macro) != 0)
660 			continue;
661 		arg = get_argument_from_call_expr(expr->args, info->param);
662 		name = expr_to_str_sym(arg, &sym);
663 		if (!name || !sym)
664 			goto free;
665 		sm = get_sm_state(my_id, name, sym);
666 
667 		if (info->action == LOCK) {
668 			if (!sm)
669 				set_start_state(name, sym, &unlocked);
670 			if (sm && sm->line != expr->pos.line)
671 				warn_on_double(sm, &locked);
672 			set_state(my_id, name, sym, &locked);
673 		} else {
674 			if (!sm)
675 				set_start_state(name, sym, &locked);
676 			if (sm && sm->line != expr->pos.line)
677 				warn_on_double(sm, &unlocked);
678 			set_state(my_id, name, sym, &unlocked);
679 		}
680 		ret = true;
681 free:
682 		free_string(name);
683 		return ret;
684 	}
685 	return false;
686 }
687 
do_lock(const char * name,struct symbol * sym,struct lock_info * info)688 static void do_lock(const char *name, struct symbol *sym, struct lock_info *info)
689 {
690 	struct sm_state *sm;
691 
692 	if (handle_macro_lock_unlock())
693 		return;
694 
695 	add_tracker(&locks, my_id, name, sym);
696 
697 	sm = get_sm_state(my_id, name, sym);
698 	if (!sm)
699 		set_start_state(name, sym, &unlocked);
700 	warn_on_double(sm, &locked);
701 	set_state(my_id, name, sym, &locked);
702 }
703 
do_lock_failed(const char * name,struct symbol * sym)704 static void do_lock_failed(const char *name, struct symbol *sym)
705 {
706 	add_tracker(&locks, my_id, name, sym);
707 	set_state(my_id, name, sym, &unlocked);
708 }
709 
do_unlock(const char * name,struct symbol * sym,struct lock_info * info)710 static void do_unlock(const char *name, struct symbol *sym, struct lock_info *info)
711 {
712 	struct sm_state *sm;
713 
714 	if (__path_is_null())
715 		return;
716 
717 	if (handle_macro_lock_unlock())
718 		return;
719 
720 	add_tracker(&locks, my_id, name, sym);
721 	sm = get_sm_state(my_id, name, sym);
722 	if (!sm) {
723 		sm = get_best_match(name, UNLOCK);
724 		if (sm) {
725 			name = sm->name;
726 			sym = sm->sym;
727 		}
728 	}
729 	if (!sm)
730 		set_start_state(name, sym, &locked);
731 	warn_on_double(sm, &unlocked);
732 	set_state(my_id, name, sym, &unlocked);
733 }
734 
do_restore(const char * name,struct symbol * sym,struct lock_info * info)735 static void do_restore(const char *name, struct symbol *sym, struct lock_info *info)
736 {
737 	if (__path_is_null())
738 		return;
739 
740 	if (!get_state(my_id, name, sym))
741 		set_start_state(name, sym, &locked);
742 
743 	add_tracker(&locks, my_id, name, sym);
744 	set_state(my_id, name, sym, &restore);
745 }
746 
match_lock_held(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)747 static void match_lock_held(const char *fn, struct expression *call_expr,
748 			    struct expression *assign_expr, void *_index)
749 {
750 	int index = PTR_INT(_index);
751 	struct lock_info *lock = &lock_table[index];
752 	char *lock_name;
753 	struct symbol *sym;
754 
755 	if (lock->arg == NO_ARG) {
756 		lock_name = get_full_name(NULL, index, &sym);
757 	} else if (lock->arg == RETURN_VAL) {
758 		if (!assign_expr)
759 			return;
760 		lock_name = get_full_name(assign_expr, index, &sym);
761 	} else {
762 		lock_name = get_full_name(call_expr, index, &sym);
763 	}
764 	if (!lock_name)
765 		return;
766 	do_lock(lock_name, sym, lock);
767 	free_string(lock_name);
768 }
769 
match_lock_failed(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)770 static void match_lock_failed(const char *fn, struct expression *call_expr,
771 			struct expression *assign_expr, void *_index)
772 {
773 	int index = PTR_INT(_index);
774 	struct lock_info *lock = &lock_table[index];
775 	char *lock_name;
776 	struct symbol *sym;
777 
778 	if (lock->arg == NO_ARG) {
779 		lock_name = get_full_name(NULL, index, &sym);
780 	} else if (lock->arg == RETURN_VAL) {
781 		if (!assign_expr)
782 			return;
783 		lock_name = get_full_name(assign_expr, index, &sym);
784 	} else {
785 		lock_name = get_full_name(call_expr, index, &sym);
786 	}
787 	if (!lock_name)
788 		return;
789 	do_lock_failed(lock_name, sym);
790 	free_string(lock_name);
791 }
792 
match_returns_locked(const char * fn,struct expression * expr,void * _index)793 static void match_returns_locked(const char *fn, struct expression *expr,
794 				      void *_index)
795 {
796 	int index = PTR_INT(_index);
797 	struct lock_info *lock = &lock_table[index];
798 	char *full_name;
799 	struct symbol *sym;
800 
801 	if (lock->arg != RETURN_VAL)
802 		return;
803 	full_name = get_full_name(expr, index, &sym);
804 	if (!full_name)
805 		return;
806 	do_lock(full_name, sym, lock);
807 }
808 
match_lock_unlock(const char * fn,struct expression * expr,void * _index)809 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
810 {
811 	int index = PTR_INT(_index);
812 	struct lock_info *lock = &lock_table[index];
813 	char *full_name;
814 	struct symbol *sym;
815 
816 	full_name = get_full_name(expr, index, &sym);
817 	if (!full_name)
818 		return;
819 	switch (lock->action) {
820 	case LOCK:
821 		do_lock(full_name, sym, lock);
822 		break;
823 	case UNLOCK:
824 		do_unlock(full_name, sym, lock);
825 		break;
826 	case RESTORE:
827 		do_restore(full_name, sym, lock);
828 		break;
829 	}
830 	free_string(full_name);
831 }
832 
get_start_state(struct sm_state * sm)833 static struct smatch_state *get_start_state(struct sm_state *sm)
834 {
835 	struct smatch_state *orig;
836 
837 	orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
838 	if (orig)
839 		return orig;
840 	return &undefined;
841 }
842 
get_param_lock_name(struct sm_state * sm,struct expression * expr,const char ** name)843 static int get_param_lock_name(struct sm_state *sm, struct expression *expr,
844 			       const char **name)
845 {
846 	char *other_name;
847 	struct symbol *other_sym;
848 	const char *param_name;
849 	int param;
850 
851 	*name = sm->name;
852 
853 	param = get_param_num_from_sym(sm->sym);
854 	if (param >= 0) {
855 		param_name = get_param_name(sm);
856 		if (param_name)
857 			*name = param_name;
858 		return param;
859 	}
860 
861 	if (expr) {
862 		struct symbol *ret_sym;
863 		char *ret_str;
864 
865 		ret_str = expr_to_str_sym(expr, &ret_sym);
866 		if (ret_str && ret_sym == sm->sym) {
867 			param_name = state_name_to_param_name(sm->name, ret_str);
868 			if (param_name) {
869 				free_string(ret_str);
870 				*name = param_name;
871 				return -1;
872 			}
873 		}
874 		free_string(ret_str);
875 	}
876 
877 	other_name = get_other_name_sym(sm->name, sm->sym, &other_sym);
878 	if (!other_name)
879 		return -2;
880 	param = get_param_num_from_sym(other_sym);
881 	if (param < 0)
882 		return -2;
883 
884 	param_name = get_param_name_var_sym(other_name, other_sym);
885 	free_string(other_name);
886 	if (param_name)
887 		*name = param_name;
888 	return param;
889 }
890 
get_db_type(struct sm_state * sm)891 static int get_db_type(struct sm_state *sm)
892 {
893 	if (sm->state == get_start_state(sm)) {
894 		if (sm->state == &locked)
895 			return KNOWN_LOCKED;
896 		if (sm->state == &unlocked)
897 			return KNOWN_UNLOCKED;
898 	}
899 
900 	if (sm->state == &locked)
901 		return LOCKED;
902 	if (sm->state == &unlocked)
903 		return UNLOCKED;
904 	if (sm->state == &restore)
905 		return LOCK_RESTORED;
906 	return LOCKED;
907 }
908 
match_return_info(int return_id,char * return_ranges,struct expression * expr)909 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
910 {
911 	struct sm_state *sm;
912 	const char *param_name;
913 	int param;
914 
915 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
916 		if (sm->state != &locked &&
917 		    sm->state != &unlocked &&
918 		    sm->state != &restore)
919 			continue;
920 
921 		param = get_param_lock_name(sm, expr, &param_name);
922 		sql_insert_return_states(return_id, return_ranges,
923 					 get_db_type(sm),
924 					 param, param_name, "");
925 	} END_FOR_EACH_SM(sm);
926 }
927 
928 enum {
929 	ERR_PTR, VALID_PTR, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS,
930 };
931 
is_EINTR(struct range_list * rl)932 static bool is_EINTR(struct range_list *rl)
933 {
934 	sval_t sval;
935 
936 	if (!rl_to_sval(rl, &sval))
937 		return false;
938 	return sval.value == -4;
939 }
940 
success_fail_positive(struct range_list * rl)941 static int success_fail_positive(struct range_list *rl)
942 {
943 	/* void returns are the same as success (zero in the kernel) */
944 	if (!rl)
945 		return ZERO;
946 
947 	if (rl_type(rl)->type != SYM_PTR && sval_is_negative(rl_min(rl)))
948 		return NEGATIVE;
949 
950 	if (rl_min(rl).value == 0 && rl_max(rl).value == 0)
951 		return ZERO;
952 
953 	if (is_err_ptr(rl_min(rl)) &&
954 	    is_err_ptr(rl_max(rl)))
955 		return ERR_PTR;
956 
957 	/*
958 	 * Trying to match ERR_PTR(ret) but without the expression struct.
959 	 * Ugly...
960 	 */
961 	if (type_bits(&long_ctype) == 64 &&
962 	    rl_type(rl)->type == SYM_PTR &&
963 	    rl_min(rl).value == INT_MIN)
964 		return ERR_PTR;
965 
966 	return POSITIVE;
967 }
968 
sym_in_lock_table(struct symbol * sym)969 static bool sym_in_lock_table(struct symbol *sym)
970 {
971 	int i;
972 
973 	if (!sym || !sym->ident)
974 		return false;
975 
976 	for (i = 0; lock_table[i].function != NULL; i++) {
977 		if (strcmp(lock_table[i].function, sym->ident->name) == 0)
978 			return true;
979 	}
980 	return false;
981 }
982 
func_in_lock_table(struct expression * expr)983 static bool func_in_lock_table(struct expression *expr)
984 {
985 	if (expr->type != EXPR_SYMBOL)
986 		return false;
987 	return sym_in_lock_table(expr->symbol);
988 }
989 
check_lock(char * name,struct symbol * sym)990 static void check_lock(char *name, struct symbol *sym)
991 {
992 	struct range_list *locked_lines = NULL;
993 	struct range_list *unlocked_lines = NULL;
994 	int locked_buckets[NUM_BUCKETS] = {};
995 	int unlocked_buckets[NUM_BUCKETS] = {};
996 	struct stree *stree, *orig;
997 	struct sm_state *return_sm;
998 	struct sm_state *sm;
999 	sval_t line = sval_type_val(&int_ctype, 0);
1000 	int bucket;
1001 	int i;
1002 
1003 	if (sym_in_lock_table(cur_func_sym))
1004 		return;
1005 
1006 	FOR_EACH_PTR(get_all_return_strees(), stree) {
1007 		orig = __swap_cur_stree(stree);
1008 
1009 		if (is_impossible_path())
1010 			goto swap_stree;
1011 
1012 		return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
1013 		if (!return_sm)
1014 			goto swap_stree;
1015 		line.value = return_sm->line;
1016 
1017 		sm = get_sm_state(my_id, name, sym);
1018 		if (!sm)
1019 			goto swap_stree;
1020 
1021 		if (parent_is_gone_var_sym(sm->name, sm->sym))
1022 			goto swap_stree;
1023 
1024 		if (sm->state != &locked &&
1025 		    sm->state != &unlocked &&
1026 		    sm->state != &restore)
1027 			goto swap_stree;
1028 
1029 		if ((sm->state == &unlocked || sm->state == &restore) &&
1030 		    is_EINTR(estate_rl(return_sm->state)))
1031 			goto swap_stree;
1032 
1033 		bucket = success_fail_positive(estate_rl(return_sm->state));
1034 		if (sm->state == &locked) {
1035 			add_range(&locked_lines, line, line);
1036 			locked_buckets[bucket] = true;
1037 		}
1038 		if (sm->state == &unlocked || sm->state == &restore) {
1039 			add_range(&unlocked_lines, line, line);
1040 			unlocked_buckets[bucket] = true;
1041 		}
1042 swap_stree:
1043 		__swap_cur_stree(orig);
1044 	} END_FOR_EACH_PTR(stree);
1045 
1046 
1047 	if (!locked_lines || !unlocked_lines)
1048 		return;
1049 
1050 	for (i = 0; i < NUM_BUCKETS; i++) {
1051 		if (locked_buckets[i] && unlocked_buckets[i])
1052 			goto complain;
1053 	}
1054 	if (locked_buckets[NEGATIVE] &&
1055 	    (unlocked_buckets[ZERO] || unlocked_buckets[POSITIVE]))
1056 		goto complain;
1057 
1058 	if (locked_buckets[ERR_PTR])
1059 		goto complain;
1060 
1061 	return;
1062 
1063 complain:
1064 	sm_msg("warn: inconsistent returns '%s'.", name);
1065 	sm_printf("  Locked on  : %s\n", show_rl(locked_lines));
1066 	sm_printf("  Unlocked on: %s\n", show_rl(unlocked_lines));
1067 }
1068 
match_func_end(struct symbol * sym)1069 static void match_func_end(struct symbol *sym)
1070 {
1071 	struct tracker *tracker;
1072 
1073 	FOR_EACH_PTR(locks, tracker) {
1074 		check_lock(tracker->name, tracker->sym);
1075 	} END_FOR_EACH_PTR(tracker);
1076 }
1077 
register_lock(int index)1078 static void register_lock(int index)
1079 {
1080 	struct lock_info *lock = &lock_table[index];
1081 	void *idx = INT_PTR(index);
1082 
1083 	if (lock->return_type == ret_one) {
1084 		return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
1085 		return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
1086 	} else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
1087 		add_function_assign_hook(lock->function, &match_returns_locked, idx);
1088 	} else if (lock->return_type == ret_any) {
1089 		add_function_hook(lock->function, &match_lock_unlock, idx);
1090 	} else if (lock->return_type == ret_zero) {
1091 		return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
1092 		return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
1093 	} else if (lock->return_type == ret_valid_ptr) {
1094 		return_implies_state_sval(lock->function, valid_ptr_min_sval, valid_ptr_max_sval, &match_lock_held, idx);
1095 	}
1096 }
1097 
load_table(struct lock_info * lock_table)1098 static void load_table(struct lock_info *lock_table)
1099 {
1100 	int i;
1101 
1102 	for (i = 0; lock_table[i].function != NULL; i++) {
1103 		if (lock_table[i].action == LOCK)
1104 			register_lock(i);
1105 		else
1106 			add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
1107 	}
1108 }
1109 
db_param_locked_unlocked(struct expression * expr,int param,char * key,char * value,enum action lock_unlock)1110 static void db_param_locked_unlocked(struct expression *expr, int param, char *key, char *value, enum action lock_unlock)
1111 {
1112 	struct expression *call, *arg;
1113 	char *name;
1114 	struct symbol *sym;
1115 
1116 	call = expr;
1117 	while (call->type == EXPR_ASSIGNMENT)
1118 		call = strip_expr(call->right);
1119 	if (call->type != EXPR_CALL)
1120 		return;
1121 
1122 	if (func_in_lock_table(call->fn))
1123 		return;
1124 
1125 	if (param == -2) {
1126 		use_best_match(key, lock_unlock);
1127 		return;
1128 	}
1129 
1130 	if (param == -1) {
1131 		if (expr->type != EXPR_ASSIGNMENT)
1132 			return;
1133 		name = get_variable_from_key(expr->left, key, &sym);
1134 	} else {
1135 		arg = get_argument_from_call_expr(call->args, param);
1136 		if (!arg)
1137 			return;
1138 
1139 		name = get_variable_from_key(arg, key, &sym);
1140 	}
1141 	if (!name || !sym)
1142 		goto free;
1143 
1144 	if (lock_unlock == LOCK)
1145 		do_lock(name, sym, NULL);
1146 	else if (lock_unlock == UNLOCK)
1147 		do_unlock(name, sym, NULL);
1148 	else if (lock_unlock == RESTORE)
1149 		do_restore(name, sym, NULL);
1150 
1151 free:
1152 	free_string(name);
1153 }
1154 
db_param_locked(struct expression * expr,int param,char * key,char * value)1155 static void db_param_locked(struct expression *expr, int param, char *key, char *value)
1156 {
1157 	db_param_locked_unlocked(expr, param, key, value, LOCK);
1158 }
1159 
db_param_unlocked(struct expression * expr,int param,char * key,char * value)1160 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
1161 {
1162 	db_param_locked_unlocked(expr, param, key, value, UNLOCK);
1163 }
1164 
db_param_restore(struct expression * expr,int param,char * key,char * value)1165 static void db_param_restore(struct expression *expr, int param, char *key, char *value)
1166 {
1167 	db_param_locked_unlocked(expr, param, key, value, RESTORE);
1168 }
1169 
get_caller_param_lock_name(struct expression * call,struct sm_state * sm,const char ** name)1170 static int get_caller_param_lock_name(struct expression *call, struct sm_state *sm, const char **name)
1171 {
1172 	struct expression *arg;
1173 	char *arg_name;
1174 	int param;
1175 
1176 	param = 0;
1177 	FOR_EACH_PTR(call->args, arg) {
1178 		arg_name = sm_to_arg_name(arg, sm);
1179 		if (arg_name) {
1180 			*name = arg_name;
1181 			return param;
1182 		}
1183 		param++;
1184 	} END_FOR_EACH_PTR(arg);
1185 
1186 	*name = sm->name;
1187 	return -2;
1188 }
1189 
match_call_info(struct expression * expr)1190 static void match_call_info(struct expression *expr)
1191 {
1192 	struct sm_state *sm;
1193 	const char *param_name;
1194 	int locked_type;
1195 	int param;
1196 
1197 	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
1198 		param = get_caller_param_lock_name(expr, sm, &param_name);
1199 		if (sm->state == &locked)
1200 			locked_type = LOCKED;
1201 		else if (sm->state == &half_locked ||
1202 			 slist_has_state(sm->possible, &locked))
1203 			locked_type = HALF_LOCKED;
1204 		else
1205 			continue;
1206 		sql_insert_caller_info(expr, locked_type, param, param_name, "xxx type");
1207 
1208 	} END_FOR_EACH_SM(sm);
1209 }
1210 
match_save_states(struct expression * expr)1211 static void match_save_states(struct expression *expr)
1212 {
1213 	push_stree(&saved_stack, start_states);
1214 	start_states = NULL;
1215 }
1216 
match_restore_states(struct expression * expr)1217 static void match_restore_states(struct expression *expr)
1218 {
1219 	start_states = pop_stree(&saved_stack);
1220 }
1221 
match_after_func(struct symbol * sym)1222 static void match_after_func(struct symbol *sym)
1223 {
1224 	free_stree(&start_states);
1225 }
1226 
match_dma_resv_lock_NULL(const char * fn,struct expression * call_expr,struct expression * assign_expr,void * _index)1227 static void match_dma_resv_lock_NULL(const char *fn, struct expression *call_expr,
1228 				     struct expression *assign_expr, void *_index)
1229 {
1230 	struct expression *lock, *ctx;
1231 	char *lock_name;
1232 	struct symbol *sym;
1233 
1234 	lock = get_argument_from_call_expr(call_expr->args, 0);
1235 	ctx = get_argument_from_call_expr(call_expr->args, 1);
1236 	if (!expr_is_zero(ctx))
1237 		return;
1238 
1239 	lock_name = lock_to_name_sym(lock, &sym);
1240 	if (!lock_name || !sym)
1241 		goto free;
1242 	do_lock(lock_name, sym, NULL);
1243 free:
1244 	free_string(lock_name);
1245 }
1246 
1247 /* print_held_locks() is used in check_call_tree.c */
print_held_locks(void)1248 void print_held_locks(void)
1249 {
1250 	struct stree *stree;
1251 	struct sm_state *sm;
1252 	int i = 0;
1253 
1254 	stree = __get_cur_stree();
1255 	FOR_EACH_MY_SM(my_id, stree, sm) {
1256 		if (sm->state != &locked)
1257 			continue;
1258 		if (i++)
1259 			sm_printf(" ");
1260 		sm_printf("'%s'", sm->name);
1261 	} END_FOR_EACH_SM(sm);
1262 }
1263 
check_locking(int id)1264 void check_locking(int id)
1265 {
1266 	my_id = id;
1267 
1268 	if (option_project != PROJ_KERNEL)
1269 		return;
1270 
1271 	load_table(lock_table);
1272 
1273 	set_dynamic_states(my_id);
1274 	add_unmatched_state_hook(my_id, &unmatched_state);
1275 	add_pre_merge_hook(my_id, &pre_merge_hook);
1276 	add_merge_hook(my_id, &merge_func);
1277 	add_modification_hook(my_id, &reset);
1278 
1279 	add_hook(&match_func_end, END_FUNC_HOOK);
1280 
1281 	add_hook(&match_after_func, AFTER_FUNC_HOOK);
1282 	add_hook(&match_save_states, INLINE_FN_START);
1283 	add_hook(&match_restore_states, INLINE_FN_END);
1284 
1285 	add_hook(&match_call_info, FUNCTION_CALL_HOOK);
1286 
1287 	add_split_return_callback(match_return_info);
1288 	select_return_states_hook(LOCKED, &db_param_locked);
1289 	select_return_states_hook(UNLOCKED, &db_param_unlocked);
1290 	select_return_states_hook(LOCK_RESTORED, &db_param_restore);
1291 
1292 	return_implies_state("dma_resv_lock", -4095, -1, &match_dma_resv_lock_NULL, 0);
1293 }
1294