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