Print this page
11506 smatch resync
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 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 /*
19 19 * This test checks that locks are held the same across all returns.
20 20 *
21 21 * Of course, some functions are designed to only hold the locks on success.
22 22 * Oh well... We can rewrite it later if we want.
23 23 *
24 24 * The list of wine locking functions came from an earlier script written
25 25 * by Michael Stefaniuc.
26 26 *
27 27 */
28 28
29 29 #include "parse.h"
30 30 #include "smatch.h"
31 31 #include "smatch_extra.h"
32 32 #include "smatch_slist.h"
33 33
34 34 static int my_id;
35 35
36 36 static int func_has_transition;
37 37
38 38 STATE(locked);
39 39 STATE(start_state);
40 40 STATE(unlocked);
41 41 STATE(impossible);
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
42 42
43 43 enum action {
44 44 LOCK,
45 45 UNLOCK,
46 46 };
47 47
48 48 enum return_type {
49 49 ret_any,
50 50 ret_non_zero,
51 51 ret_zero,
52 + ret_one,
52 53 ret_negative,
53 54 ret_positive,
54 55 };
55 56
56 57 #define RETURN_VAL -1
57 58 #define NO_ARG -2
58 59
59 60 struct lock_info {
60 61 const char *function;
61 62 enum action action;
62 63 const char *name;
63 64 int arg;
64 65 enum return_type return_type;
65 66 };
66 67
67 68 static struct lock_info wine_lock_table[] = {
68 69 {"create_window_handle", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
69 70 {"WIN_GetPtr", LOCK, "create_window_handle", RETURN_VAL, ret_non_zero},
70 71 {"WIN_ReleasePtr", UNLOCK, "create_window_handle", 0, ret_any},
71 72 {"EnterCriticalSection", LOCK, "CriticalSection", 0, ret_any},
72 73 {"LeaveCriticalSection", UNLOCK, "CriticalSection", 0, ret_any},
73 74 {"RtlEnterCriticalSection", LOCK, "RtlCriticalSection", 0, ret_any},
74 75 {"RtlLeaveCriticalSection", UNLOCK, "RtlCriticalSection", 0, ret_any},
75 76 {"GDI_GetObjPtr", LOCK, "GDI_Get", 0, ret_non_zero},
76 77 {"GDI_ReleaseObj", UNLOCK, "GDI_Get", 0, ret_any},
77 78 {"LdrLockLoaderLock", LOCK, "LdrLockLoaderLock", 2, ret_any},
78 79 {"LdrUnlockLoaderLock", UNLOCK, "LdrLockLoaderLock", 1, ret_any},
79 80 {"_lock", LOCK, "_lock", 0, ret_any},
80 81 {"_unlock", UNLOCK, "_lock", 0, ret_any},
81 82 {"msiobj_lock", LOCK, "msiobj_lock", 0, ret_any},
82 83 {"msiobj_unlock", UNLOCK, "msiobj_lock", 0, ret_any},
83 84 {"RtlAcquirePebLock", LOCK, "PebLock", NO_ARG, ret_any},
84 85 {"RtlReleasePebLock", UNLOCK, "PebLock", NO_ARG, ret_any},
85 86 {"server_enter_uninterrupted_section", LOCK, "server_uninterrupted_section", 0, ret_any},
86 87 {"server_leave_uninterrupted_section", UNLOCK, "server_uninterrupted_section", 0, ret_any},
87 88 {"RtlLockHeap", LOCK, "RtlLockHeap", 0, ret_any},
88 89 {"RtlUnlockHeap", UNLOCK, "RtlLockHeap", 0, ret_any},
89 90 {"_EnterSysLevel", LOCK, "SysLevel", 0, ret_any},
90 91 {"_LeaveSysLevel", UNLOCK, "SysLevel", 0, ret_any},
91 92 {"USER_Lock", LOCK, "USER_Lock", NO_ARG, ret_any},
92 93 {"USER_Unlock", UNLOCK, "USER_Lock", NO_ARG, ret_any},
93 94 {"wine_tsx11_lock", LOCK, "wine_tsx11_lock", NO_ARG, ret_any},
94 95 {"wine_tsx11_unlock", UNLOCK, "wine_tsx11_lock", NO_ARG, ret_any},
95 96 {"wine_tsx11_lock_ptr", LOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
96 97 {"wine_tsx11_unlock_ptr", UNLOCK, "wine_tsx11_lock_ptr", NO_ARG, ret_any},
97 98 {"wined3d_mutex_lock", LOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
98 99 {"wined3d_mutex_unlock", UNLOCK, "wined3d_mutex_lock", NO_ARG, ret_any},
99 100 {"X11DRV_DIB_Lock", LOCK, "X11DRV_DIB_Lock", 0, ret_any},
100 101 {"X11DRV_DIB_Unlock", UNLOCK, "X11DRV_DIB_Lock", 0, ret_any},
101 102 };
102 103
103 104 static struct lock_info kernel_lock_table[] = {
104 105 {"lock_kernel", LOCK, "BKL", NO_ARG, ret_any},
105 106 {"unlock_kernel", UNLOCK, "BKL", NO_ARG, ret_any},
106 107
107 108 {"spin_lock", LOCK, "spin_lock", 0, ret_any},
108 109 {"spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
109 110 {"spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
110 111 {"_spin_lock", LOCK, "spin_lock", 0, ret_any},
111 112 {"_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
112 113 {"_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
113 114 {"__spin_lock", LOCK, "spin_lock", 0, ret_any},
114 115 {"__spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
115 116 {"__spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
116 117 {"raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
117 118 {"raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
118 119 {"_raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
119 120 {"_raw_spin_lock_nested", LOCK, "spin_lock", 0, ret_any},
120 121 {"_raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
121 122 {"__raw_spin_lock", LOCK, "spin_lock", 0, ret_any},
122 123 {"__raw_spin_unlock", UNLOCK, "spin_lock", 0, ret_any},
123 124
124 125 {"spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
125 126 {"spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
126 127 {"_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
127 128 {"_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
128 129 {"__spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
129 130 {"__spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
130 131 {"_raw_spin_lock_irq", LOCK, "spin_lock", 0, ret_any},
131 132 {"_raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
132 133 {"__raw_spin_unlock_irq", UNLOCK, "spin_lock", 0, ret_any},
133 134 {"spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
134 135 {"spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
135 136 {"_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
136 137 {"_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
137 138 {"__spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
138 139 {"__spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
139 140 {"_raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
140 141 {"_raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
141 142 {"__raw_spin_lock_irqsave", LOCK, "spin_lock", 0, ret_any},
142 143 {"__raw_spin_unlock_irqrestore", UNLOCK, "spin_lock", 0, ret_any},
143 144 {"spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
↓ open down ↓ |
82 lines elided |
↑ open up ↑ |
144 145 {"_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
145 146 {"__spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
146 147 {"_raw_spin_lock_irqsave_nested", LOCK, "spin_lock", 0, ret_any},
147 148 {"spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
148 149 {"spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
149 150 {"_spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
150 151 {"_spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
151 152 {"__spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
152 153 {"__spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
153 154
154 - {"spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
155 - {"_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
156 - {"__spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
157 - {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
158 - {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
159 - {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_non_zero},
160 - {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_non_zero},
161 - {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
162 - {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
163 - {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
164 - {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
165 - {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_non_zero},
155 + {"spin_trylock", LOCK, "spin_lock", 0, ret_one},
156 + {"_spin_trylock", LOCK, "spin_lock", 0, ret_one},
157 + {"__spin_trylock", LOCK, "spin_lock", 0, ret_one},
158 + {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
159 + {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
160 + {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_one},
161 + {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_one},
162 + {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
163 + {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
164 + {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
165 + {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
166 + {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_one},
166 167
167 168 {"read_lock", LOCK, "read_lock", 0, ret_any},
168 169 {"read_unlock", UNLOCK, "read_lock", 0, ret_any},
169 170 {"_read_lock", LOCK, "read_lock", 0, ret_any},
170 171 {"_read_unlock", UNLOCK, "read_lock", 0, ret_any},
171 172 {"__read_lock", LOCK, "read_lock", 0, ret_any},
172 173 {"__read_unlock", UNLOCK, "read_lock", 0, ret_any},
173 174 {"_raw_read_lock", LOCK, "read_lock", 0, ret_any},
174 175 {"_raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
175 176 {"__raw_read_lock", LOCK, "read_lock", 0, ret_any},
176 177 {"__raw_read_unlock", UNLOCK, "read_lock", 0, ret_any},
177 178 {"read_lock_irq", LOCK, "read_lock", 0, ret_any},
178 179 {"read_unlock_irq" , UNLOCK, "read_lock", 0, ret_any},
179 180 {"_read_lock_irq", LOCK, "read_lock", 0, ret_any},
180 181 {"_read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
181 182 {"__read_lock_irq", LOCK, "read_lock", 0, ret_any},
182 183 {"__read_unlock_irq", UNLOCK, "read_lock", 0, ret_any},
183 184 {"read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
184 185 {"read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
185 186 {"_read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
186 187 {"_read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
187 188 {"__read_lock_irqsave", LOCK, "read_lock", 0, ret_any},
188 189 {"__read_unlock_irqrestore", UNLOCK, "read_lock", 0, ret_any},
189 190 {"read_lock_bh", LOCK, "read_lock", 0, ret_any},
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
190 191 {"read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
191 192 {"_read_lock_bh", LOCK, "read_lock", 0, ret_any},
192 193 {"_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
193 194 {"__read_lock_bh", LOCK, "read_lock", 0, ret_any},
194 195 {"__read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
195 196 {"_raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
196 197 {"_raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
197 198 {"__raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
198 199 {"__raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
199 200
200 - {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
201 - {"read_trylock", LOCK, "read_lock", 0, ret_non_zero},
202 - {"_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
203 - {"raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
204 - {"_raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
205 - {"__raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
206 - {"__read_trylock", LOCK, "read_lock", 0, ret_non_zero},
201 + {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
202 + {"read_trylock", LOCK, "read_lock", 0, ret_one},
203 + {"_read_trylock", LOCK, "read_lock", 0, ret_one},
204 + {"raw_read_trylock", LOCK, "read_lock", 0, ret_one},
205 + {"_raw_read_trylock", LOCK, "read_lock", 0, ret_one},
206 + {"__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
207 + {"__read_trylock", LOCK, "read_lock", 0, ret_one},
207 208
208 209 {"write_lock", LOCK, "write_lock", 0, ret_any},
209 210 {"write_unlock", UNLOCK, "write_lock", 0, ret_any},
210 211 {"_write_lock", LOCK, "write_lock", 0, ret_any},
211 212 {"_write_unlock", UNLOCK, "write_lock", 0, ret_any},
212 213 {"__write_lock", LOCK, "write_lock", 0, ret_any},
213 214 {"__write_unlock", UNLOCK, "write_lock", 0, ret_any},
214 215 {"write_lock_irq", LOCK, "write_lock", 0, ret_any},
215 216 {"write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
216 217 {"_write_lock_irq", LOCK, "write_lock", 0, ret_any},
217 218 {"_write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
218 219 {"__write_lock_irq", LOCK, "write_lock", 0, ret_any},
219 220 {"__write_unlock_irq", UNLOCK, "write_lock", 0, ret_any},
220 221 {"write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
221 222 {"write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
222 223 {"_write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
223 224 {"_write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
224 225 {"__write_lock_irqsave", LOCK, "write_lock", 0, ret_any},
225 226 {"__write_unlock_irqrestore", UNLOCK, "write_lock", 0, ret_any},
226 227 {"write_lock_bh", LOCK, "write_lock", 0, ret_any},
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
227 228 {"write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
228 229 {"_write_lock_bh", LOCK, "write_lock", 0, ret_any},
229 230 {"_write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
230 231 {"__write_lock_bh", LOCK, "write_lock", 0, ret_any},
231 232 {"__write_unlock_bh", UNLOCK, "write_lock", 0, ret_any},
232 233 {"_raw_write_lock", LOCK, "write_lock", 0, ret_any},
233 234 {"__raw_write_lock", LOCK, "write_lock", 0, ret_any},
234 235 {"_raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
235 236 {"__raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
236 237
237 - {"write_trylock", LOCK, "write_lock", 0, ret_non_zero},
238 - {"_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
239 - {"raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
240 - {"_raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
241 - {"__write_trylock", LOCK, "write_lock", 0, ret_non_zero},
242 - {"__raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
238 + {"write_trylock", LOCK, "write_lock", 0, ret_one},
239 + {"_write_trylock", LOCK, "write_lock", 0, ret_one},
240 + {"raw_write_trylock", LOCK, "write_lock", 0, ret_one},
241 + {"_raw_write_trylock", LOCK, "write_lock", 0, ret_one},
242 + {"__write_trylock", LOCK, "write_lock", 0, ret_one},
243 + {"__raw_write_trylock", LOCK, "write_lock", 0, ret_one},
243 244
244 245 {"down", LOCK, "sem", 0, ret_any},
245 246 {"up", UNLOCK, "sem", 0, ret_any},
246 247 {"down_trylock", LOCK, "sem", 0, ret_zero},
247 248 {"down_timeout", LOCK, "sem", 0, ret_zero},
248 249 {"down_interruptible", LOCK, "sem", 0, ret_zero},
249 250
251 +
252 + {"down_write", LOCK, "rw_sem", 0, ret_any},
253 + {"downgrade_write", UNLOCK, "rw_sem", 0, ret_any},
254 + {"downgrade_write", LOCK, "read_sem", 0, ret_any},
255 + {"up_write", UNLOCK, "rw_sem", 0, ret_any},
256 + {"down_write_trylock", LOCK, "rw_sem", 0, ret_one},
257 + {"down_write_killable", LOCK, "rw_sem", 0, ret_zero},
258 + {"down_read", LOCK, "read_sem", 0, ret_any},
259 + {"down_read_trylock", LOCK, "read_sem", 0, ret_one},
260 + {"down_read_killable", LOCK, "read_sem", 0, ret_zero},
261 + {"up_read", UNLOCK, "read_sem", 0, ret_any},
262 +
250 263 {"mutex_lock", LOCK, "mutex", 0, ret_any},
264 + {"mutex_lock_io", LOCK, "mutex", 0, ret_any},
251 265 {"mutex_unlock", UNLOCK, "mutex", 0, ret_any},
252 266 {"mutex_lock_nested", LOCK, "mutex", 0, ret_any},
267 + {"mutex_lock_io_nested", LOCK, "mutex", 0, ret_any},
253 268
254 269 {"mutex_lock_interruptible", LOCK, "mutex", 0, ret_zero},
255 270 {"mutex_lock_interruptible_nested", LOCK, "mutex", 0, ret_zero},
256 271 {"mutex_lock_killable", LOCK, "mutex", 0, ret_zero},
257 272 {"mutex_lock_killable_nested", LOCK, "mutex", 0, ret_zero},
258 273
259 - {"mutex_trylock", LOCK, "mutex", 0, ret_non_zero},
274 + {"mutex_trylock", LOCK, "mutex", 0, ret_one},
260 275
261 276 {"raw_local_irq_disable", LOCK, "irq", NO_ARG, ret_any},
262 277 {"raw_local_irq_enable", UNLOCK, "irq", NO_ARG, ret_any},
263 278 {"spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
264 279 {"spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
265 280 {"_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
266 281 {"_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
267 282 {"__spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
268 283 {"__spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
269 284 {"_raw_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
270 285 {"_raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
271 286 {"__raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
272 - {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_non_zero},
287 + {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_one},
273 288 {"read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
274 289 {"read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
275 290 {"_read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
276 291 {"_read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
277 292 {"__read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
278 293 {"__read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
279 294 {"write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
280 295 {"write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
281 296 {"_write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
282 297 {"_write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
283 298 {"__write_lock_irq", LOCK, "irq", NO_ARG, ret_any},
284 299 {"__write_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
285 300
286 301 {"arch_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
287 302 {"arch_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
288 303 {"__raw_local_irq_save", LOCK, "irqsave", RETURN_VAL, ret_any},
289 304 {"raw_local_irq_restore", UNLOCK, "irqsave", 0, ret_any},
290 305 {"spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
291 306 {"spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
292 307 {"spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
293 308 {"spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
294 309 {"_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
295 310 {"_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
296 311 {"_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
297 312 {"_spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
298 313 {"__spin_lock_irqsave_nested", LOCK, "irqsave", 1, ret_any},
299 314 {"__spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
300 315 {"__spin_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
301 316 {"_raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
302 317 {"_raw_spin_lock_irqsave", LOCK, "irqsave", 1, ret_any},
303 318 {"_raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
304 319 {"__raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
305 320 {"__raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
306 321 {"_raw_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
307 - {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_non_zero},
322 + {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_one},
308 323 {"read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
309 324 {"read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
310 325 {"read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
311 326 {"_read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
312 327 {"_read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
313 328 {"_read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
314 329 {"__read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
315 330 {"__read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
316 331 {"write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
317 332 {"write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
318 333 {"write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
319 334 {"_write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
320 335 {"_write_lock_irqsave", LOCK, "irqsave", 1, ret_any},
321 336 {"_write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
322 337 {"__write_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
323 338 {"__write_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
324 339
325 340 {"local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
326 341 {"_local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
327 342 {"__local_bh_disable", LOCK, "bottom_half", NO_ARG, ret_any},
328 343 {"local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
329 344 {"_local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
330 345 {"__local_bh_enable", UNLOCK, "bottom_half", NO_ARG, ret_any},
331 346 {"spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
332 347 {"spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
333 348 {"_spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
334 349 {"_spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
335 350 {"__spin_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
336 351 {"__spin_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
337 352 {"read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
338 353 {"read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
339 354 {"_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
340 355 {"_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
341 356 {"__read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
342 357 {"__read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
343 358 {"_raw_read_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
344 359 {"_raw_read_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
345 360 {"write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
346 361 {"write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
347 362 {"_write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
348 363 {"_write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
349 364 {"__write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
350 365 {"__write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
351 - {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
352 - {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
353 - {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
366 + {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
367 + {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
368 + {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
354 369
355 370 {"ffs_mutex_lock", LOCK, "mutex", 0, ret_zero},
356 371 };
357 372
358 373 static struct lock_info *lock_table;
359 374
360 375 static struct tracker_list *starts_locked;
361 376 static struct tracker_list *starts_unlocked;
362 377
363 378 struct locks_on_return {
364 379 int line;
365 380 struct tracker_list *locked;
366 381 struct tracker_list *unlocked;
367 382 struct tracker_list *impossible;
368 383 struct range_list *return_values;
369 384 };
370 385 DECLARE_PTR_LIST(return_list, struct locks_on_return);
371 386 static struct return_list *all_returns;
372 387
373 388 static char *make_full_name(const char *lock, const char *var)
374 389 {
375 390 static char tmp_buf[512];
376 391
377 392 snprintf(tmp_buf, sizeof(tmp_buf), "%s:%s", lock, var);
378 393 remove_parens(tmp_buf);
379 394 return alloc_string(tmp_buf);
380 395 }
381 396
382 397 static struct expression *remove_spinlock_check(struct expression *expr)
383 398 {
384 399 if (expr->type != EXPR_CALL)
385 400 return expr;
386 401 if (expr->fn->type != EXPR_SYMBOL)
387 402 return expr;
388 403 if (strcmp(expr->fn->symbol_name->name, "spinlock_check"))
389 404 return expr;
390 405 expr = get_argument_from_call_expr(expr->args, 0);
391 406 return expr;
392 407 }
393 408
394 409 static char *get_full_name(struct expression *expr, int index)
395 410 {
396 411 struct expression *arg;
397 412 char *name = NULL;
398 413 char *full_name = NULL;
399 414 struct lock_info *lock = &lock_table[index];
400 415
401 416 if (lock->arg == RETURN_VAL) {
402 417 name = expr_to_var(expr->left);
403 418 full_name = make_full_name(lock->name, name);
404 419 } else if (lock->arg == NO_ARG) {
405 420 full_name = make_full_name(lock->name, "");
406 421 } else {
407 422 arg = get_argument_from_call_expr(expr->args, lock->arg);
408 423 if (!arg)
409 424 goto free;
410 425 arg = remove_spinlock_check(arg);
411 426 name = expr_to_str(arg);
412 427 if (!name)
413 428 goto free;
414 429 full_name = make_full_name(lock->name, name);
415 430 }
416 431 free:
417 432 free_string(name);
418 433 return full_name;
419 434 }
420 435
421 436 static struct smatch_state *get_start_state(struct sm_state *sm)
422 437 {
423 438 int is_locked = 0;
424 439 int is_unlocked = 0;
425 440
426 441 if (in_tracker_list(starts_locked, my_id, sm->name, sm->sym))
427 442 is_locked = 1;
428 443 if (in_tracker_list(starts_unlocked, my_id, sm->name, sm->sym))
429 444 is_unlocked = 1;
430 445 if (is_locked && is_unlocked)
431 446 return &undefined;
432 447 if (is_locked)
433 448 return &locked;
434 449 if (is_unlocked)
435 450 return &unlocked;
436 451 return &undefined;
437 452 }
438 453
439 454 static struct smatch_state *unmatched_state(struct sm_state *sm)
↓ open down ↓ |
76 lines elided |
↑ open up ↑ |
440 455 {
441 456 return &start_state;
442 457 }
443 458
444 459 static void pre_merge_hook(struct sm_state *sm)
445 460 {
446 461 if (is_impossible_path())
447 462 set_state(my_id, sm->name, sm->sym, &impossible);
448 463 }
449 464
465 +static bool nestable(const char *name)
466 +{
467 + if (strstr(name, "read_sem:"))
468 + return true;
469 + if (strcmp(name, "bottom_half:") == 0)
470 + return true;
471 + return false;
472 +}
473 +
450 474 static void do_lock(const char *name)
451 475 {
452 476 struct sm_state *sm;
453 477
454 478 if (__inline_fn)
455 479 return;
456 480
457 481 sm = get_sm_state(my_id, name, NULL);
458 482 if (!sm)
459 483 add_tracker(&starts_unlocked, my_id, name, NULL);
460 - if (sm && slist_has_state(sm->possible, &locked) &&
461 - strcmp(name, "bottom_half:") != 0)
484 + if (sm && slist_has_state(sm->possible, &locked) && !nestable(name))
462 485 sm_error("double lock '%s'", name);
463 486 if (sm)
464 487 func_has_transition = TRUE;
465 488 set_state(my_id, name, NULL, &locked);
466 489 }
467 490
468 491 static void do_lock_failed(const char *name)
469 492 {
470 493 struct sm_state *sm;
471 494
472 495 if (__inline_fn)
473 496 return;
474 497
475 498 sm = get_sm_state(my_id, name, NULL);
476 499 if (!sm)
477 500 add_tracker(&starts_unlocked, my_id, name, NULL);
478 501 set_state(my_id, name, NULL, &unlocked);
479 502 }
480 503
481 504 static void do_unlock(const char *name)
482 505 {
483 506 struct sm_state *sm;
484 507
485 508 if (__inline_fn)
486 509 return;
487 510 if (__path_is_null())
488 511 return;
489 512 sm = get_sm_state(my_id, name, NULL);
490 513 if (!sm)
491 514 add_tracker(&starts_locked, my_id, name, NULL);
492 515 if (sm && slist_has_state(sm->possible, &unlocked) &&
493 516 strcmp(name, "bottom_half:") != 0)
494 517 sm_error("double unlock '%s'", name);
495 518 if (sm)
496 519 func_has_transition = TRUE;
497 520 set_state(my_id, name, NULL, &unlocked);
498 521 }
499 522
500 523 static void match_lock_held(const char *fn, struct expression *call_expr,
501 524 struct expression *assign_expr, void *_index)
502 525 {
503 526 int index = PTR_INT(_index);
504 527 char *lock_name;
505 528 struct lock_info *lock = &lock_table[index];
506 529
507 530 if (lock->arg == NO_ARG) {
508 531 lock_name = get_full_name(NULL, index);
509 532 } else if (lock->arg == RETURN_VAL) {
510 533 if (!assign_expr)
511 534 return;
512 535 lock_name = get_full_name(assign_expr, index);
513 536 } else {
514 537 lock_name = get_full_name(call_expr, index);
515 538 }
516 539 if (!lock_name)
517 540 return;
518 541 do_lock(lock_name);
519 542 free_string(lock_name);
520 543 }
521 544
522 545 static void match_lock_failed(const char *fn, struct expression *call_expr,
523 546 struct expression *assign_expr, void *_index)
524 547 {
525 548 int index = PTR_INT(_index);
526 549 char *lock_name;
527 550 struct lock_info *lock = &lock_table[index];
528 551
529 552 if (lock->arg == NO_ARG) {
530 553 lock_name = get_full_name(NULL, index);
531 554 } else if (lock->arg == RETURN_VAL) {
532 555 if (!assign_expr)
533 556 return;
534 557 lock_name = get_full_name(assign_expr, index);
535 558 } else {
536 559 lock_name = get_full_name(call_expr, index);
537 560 }
538 561 if (!lock_name)
539 562 return;
540 563 do_lock_failed(lock_name);
541 564 free_string(lock_name);
542 565 }
543 566
544 567 static void match_returns_locked(const char *fn, struct expression *expr,
545 568 void *_index)
546 569 {
547 570 char *full_name = NULL;
548 571 int index = PTR_INT(_index);
549 572 struct lock_info *lock = &lock_table[index];
550 573
551 574 if (lock->arg != RETURN_VAL)
552 575 return;
553 576 full_name = get_full_name(expr, index);
554 577 do_lock(full_name);
555 578 }
556 579
557 580 static void match_lock_unlock(const char *fn, struct expression *expr, void *_index)
558 581 {
559 582 char *full_name = NULL;
560 583 int index = PTR_INT(_index);
561 584 struct lock_info *lock = &lock_table[index];
562 585
563 586 if (__inline_fn)
564 587 return;
565 588
566 589 full_name = get_full_name(expr, index);
567 590 if (!full_name)
568 591 return;
569 592 if (lock->action == LOCK)
570 593 do_lock(full_name);
571 594 else
572 595 do_unlock(full_name);
573 596 free_string(full_name);
574 597 }
575 598
576 599 static struct locks_on_return *alloc_return(struct expression *expr)
577 600 {
578 601 struct locks_on_return *ret;
579 602
580 603 ret = malloc(sizeof(*ret));
581 604 if (!get_implied_rl(expr, &ret->return_values))
582 605 ret->return_values = NULL;
583 606 ret->line = get_lineno();
584 607 ret->locked = NULL;
585 608 ret->unlocked = NULL;
586 609 ret->impossible = NULL;
587 610 return ret;
588 611 }
589 612
590 613 static int check_possible(struct sm_state *sm)
591 614 {
592 615 struct sm_state *tmp;
593 616 int islocked = 0;
594 617 int isunlocked = 0;
595 618 int undef = 0;
596 619
597 620 if (!option_spammy)
598 621 return 0;
599 622
600 623 FOR_EACH_PTR(sm->possible, tmp) {
601 624 if (tmp->state == &locked)
602 625 islocked = 1;
603 626 if (tmp->state == &unlocked)
604 627 isunlocked = 1;
605 628 if (tmp->state == &start_state) {
606 629 struct smatch_state *s;
607 630
608 631 s = get_start_state(tmp);
609 632 if (s == &locked)
610 633 islocked = 1;
611 634 else if (s == &unlocked)
612 635 isunlocked = 1;
613 636 else
614 637 undef = 1;
615 638 }
616 639 if (tmp->state == &undefined)
617 640 undef = 1; // i don't think this is possible any more.
618 641 } END_FOR_EACH_PTR(tmp);
619 642 if ((islocked && isunlocked) || undef) {
620 643 sm_warning("'%s' is sometimes locked here and sometimes unlocked.", sm->name);
621 644 return 1;
622 645 }
623 646 return 0;
624 647 }
625 648
626 649 static struct position warned_pos;
627 650
628 651 static void match_return(int return_id, char *return_ranges, struct expression *expr)
629 652 {
630 653 struct locks_on_return *ret;
631 654 struct stree *stree;
632 655 struct sm_state *tmp;
633 656
634 657 if (!final_pass)
635 658 return;
636 659 if (__inline_fn)
637 660 return;
638 661
639 662 if (expr && cmp_pos(expr->pos, warned_pos) == 0)
640 663 return;
641 664
642 665 ret = alloc_return(expr);
643 666
644 667 stree = __get_cur_stree();
645 668 FOR_EACH_MY_SM(my_id, stree, tmp) {
646 669 if (tmp->state == &locked) {
647 670 add_tracker(&ret->locked, tmp->owner, tmp->name,
648 671 tmp->sym);
649 672 } else if (tmp->state == &unlocked) {
650 673 add_tracker(&ret->unlocked, tmp->owner, tmp->name,
651 674 tmp->sym);
652 675 } else if (tmp->state == &start_state) {
653 676 struct smatch_state *s;
654 677
655 678 s = get_start_state(tmp);
656 679 if (s == &locked)
657 680 add_tracker(&ret->locked, tmp->owner, tmp->name,
658 681 tmp->sym);
659 682 if (s == &unlocked)
660 683 add_tracker(&ret->unlocked, tmp->owner,tmp->name,
661 684 tmp->sym);
662 685 } else if (tmp->state == &impossible) {
663 686 add_tracker(&ret->impossible, tmp->owner, tmp->name,
664 687 tmp->sym);
665 688 } else {
666 689 if (check_possible(tmp)) {
667 690 if (expr)
668 691 warned_pos = expr->pos;
669 692 }
670 693 }
671 694 } END_FOR_EACH_SM(tmp);
672 695 add_ptr_list(&all_returns, ret);
673 696 }
674 697
675 698 static void add_line(struct range_list **rl, int line)
676 699 {
677 700 sval_t sval = sval_type_val(&int_ctype, line);
678 701
679 702 add_range(rl, sval, sval);
680 703 }
681 704
682 705 static int line_printed(struct range_list *rl, int line)
683 706 {
684 707 sval_t sval = sval_type_val(&int_ctype, line);
685 708
686 709 return rl_has_sval(rl, sval);
687 710 }
688 711
689 712 static void print_inconsistent_returns(struct tracker *lock,
690 713 struct smatch_state *start)
691 714 {
692 715 struct locks_on_return *tmp;
693 716 struct range_list *printed = NULL;
694 717 int i;
695 718
696 719 sm_warning("inconsistent returns '%s'.", lock->name);
697 720 sm_printf(" Locked on: ");
698 721
699 722 i = 0;
700 723 FOR_EACH_PTR(all_returns, tmp) {
701 724 if (line_printed(printed, tmp->line))
702 725 continue;
703 726 if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym))
704 727 continue;
705 728 if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym)) {
706 729 if (i++)
707 730 sm_printf(" ");
708 731 sm_printf("line %d\n", tmp->line);
709 732 add_line(&printed, tmp->line);
710 733 continue;
711 734 }
712 735 if (start == &locked) {
713 736 if (i++)
714 737 sm_printf(" ");
715 738 sm_printf("line %d\n", tmp->line);
716 739 add_line(&printed, tmp->line);
717 740 }
718 741 } END_FOR_EACH_PTR(tmp);
719 742
720 743 sm_printf(" Unlocked on: ");
721 744 printed = NULL;
722 745 i = 0;
723 746 FOR_EACH_PTR(all_returns, tmp) {
724 747 if (line_printed(printed, tmp->line))
725 748 continue;
726 749 if (in_tracker_list(tmp->unlocked, lock->owner, lock->name, lock->sym)) {
727 750 if (i++)
728 751 sm_printf(" ");
729 752 sm_printf("line %d\n", tmp->line);
730 753 add_line(&printed, tmp->line);
731 754 continue;
732 755 }
733 756 if (in_tracker_list(tmp->locked, lock->owner, lock->name, lock->sym))
734 757 continue;
735 758 if (start == &unlocked) {
736 759 if (i++)
↓ open down ↓ |
265 lines elided |
↑ open up ↑ |
737 760 sm_printf(" ");
738 761 sm_printf("line %d\n", tmp->line);
739 762 add_line(&printed, tmp->line);
740 763 }
741 764 } END_FOR_EACH_PTR(tmp);
742 765 }
743 766
744 767 static int matches_return_type(struct range_list *rl, enum return_type type)
745 768 {
746 769 sval_t zero_sval = ll_to_sval(0);
770 + sval_t one_sval = ll_to_sval(1);
747 771
748 772 /* All these double negatives are super ugly! */
749 773
750 774 switch (type) {
751 775 case ret_zero:
752 776 return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(zero_sval, zero_sval));
777 + case ret_one:
778 + return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(one_sval, one_sval));
753 779 case ret_non_zero:
754 780 return !possibly_true_rl(rl, SPECIAL_EQUAL, alloc_rl(zero_sval, zero_sval));
755 781 case ret_negative:
756 782 return !possibly_true_rl(rl, SPECIAL_GTE, alloc_rl(zero_sval, zero_sval));
757 783 case ret_positive:
758 784 return !possibly_true_rl(rl, '<', alloc_rl(zero_sval, zero_sval));
759 785 case ret_any:
760 786 default:
761 787 return 1;
762 788 }
763 789 }
764 790
765 791 static int match_held(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
766 792 {
767 793 if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
768 794 return 0;
769 795 if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
770 796 return 0;
771 797 if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
772 798 return 1;
773 799 if (start == &unlocked)
774 800 return 0;
775 801 return 1;
776 802 }
777 803
778 804 static int match_released(struct tracker *lock, struct locks_on_return *this_return, struct smatch_state *start)
779 805 {
780 806 if (in_tracker_list(this_return->impossible, lock->owner, lock->name, lock->sym))
781 807 return 0;
782 808 if (in_tracker_list(this_return->unlocked, lock->owner, lock->name, lock->sym))
783 809 return 1;
784 810 if (in_tracker_list(this_return->locked, lock->owner, lock->name, lock->sym))
785 811 return 0;
786 812 if (start == &unlocked)
787 813 return 1;
788 814 return 0;
789 815 }
790 816
791 817 static int held_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
792 818 {
793 819 struct locks_on_return *tmp;
794 820
795 821 FOR_EACH_PTR(all_returns, tmp) {
796 822 if (!matches_return_type(tmp->return_values, type))
797 823 continue;
798 824 if (match_held(lock, tmp, start))
799 825 return 1;
800 826 } END_FOR_EACH_PTR(tmp);
801 827 return 0;
802 828 }
803 829
804 830 static int released_on_return(struct tracker *lock, struct smatch_state *start, enum return_type type)
805 831 {
806 832 struct locks_on_return *tmp;
807 833
808 834 FOR_EACH_PTR(all_returns, tmp) {
809 835 if (!matches_return_type(tmp->return_values, type))
810 836 continue;
811 837 if (match_released(lock, tmp, start))
812 838 return 1;
813 839 } END_FOR_EACH_PTR(tmp);
814 840 return 0;
815 841 }
816 842
817 843 static void check_returns_consistently(struct tracker *lock,
818 844 struct smatch_state *start)
819 845 {
820 846 struct symbol *type;
821 847
822 848 if (!held_on_return(lock, start, ret_any) ||
823 849 !released_on_return(lock, start, ret_any))
824 850 return;
825 851
826 852 if (held_on_return(lock, start, ret_zero) &&
827 853 !held_on_return(lock, start, ret_non_zero))
828 854 return;
829 855
830 856 if (held_on_return(lock, start, ret_positive) &&
831 857 !held_on_return(lock, start, ret_zero))
832 858 return;
833 859
834 860 if (held_on_return(lock, start, ret_positive) &&
835 861 !held_on_return(lock, start, ret_negative))
836 862 return;
837 863
838 864 type = cur_func_return_type();
839 865 if (type && type->type == SYM_PTR) {
840 866 if (held_on_return(lock, start, ret_non_zero) &&
841 867 !held_on_return(lock, start, ret_zero))
842 868 return;
843 869 }
844 870
845 871 print_inconsistent_returns(lock, start);
846 872 }
847 873
848 874 static void check_consistency(struct symbol *sym)
849 875 {
850 876 struct tracker *tmp;
851 877
852 878 FOR_EACH_PTR(starts_locked, tmp) {
853 879 if (in_tracker_list(starts_unlocked, tmp->owner, tmp->name,
854 880 tmp->sym))
855 881 sm_error("locking inconsistency. We assume "
856 882 "'%s' is both locked and unlocked at the "
857 883 "start.",
858 884 tmp->name);
859 885 } END_FOR_EACH_PTR(tmp);
860 886
861 887 FOR_EACH_PTR(starts_locked, tmp) {
862 888 check_returns_consistently(tmp, &locked);
863 889 } END_FOR_EACH_PTR(tmp);
864 890
865 891 FOR_EACH_PTR(starts_unlocked, tmp) {
866 892 check_returns_consistently(tmp, &unlocked);
867 893 } END_FOR_EACH_PTR(tmp);
868 894 }
869 895
870 896 static void clear_lists(void)
871 897 {
872 898 struct locks_on_return *tmp;
873 899
874 900 func_has_transition = FALSE;
875 901
876 902 free_trackers_and_list(&starts_locked);
877 903 free_trackers_and_list(&starts_unlocked);
878 904
879 905 FOR_EACH_PTR(all_returns, tmp) {
880 906 free_trackers_and_list(&tmp->locked);
881 907 free_trackers_and_list(&tmp->unlocked);
882 908 free(tmp);
883 909 } END_FOR_EACH_PTR(tmp);
884 910 __free_ptr_list((struct ptr_list **)&all_returns);
885 911 }
886 912
887 913 static void match_func_end(struct symbol *sym)
888 914 {
889 915 if (__inline_fn)
890 916 return;
891 917
892 918 if (func_has_transition)
893 919 check_consistency(sym);
894 920 }
895 921
896 922 static void match_after_func(struct symbol *sym)
897 923 {
898 924 if (__inline_fn)
↓ open down ↓ |
136 lines elided |
↑ open up ↑ |
899 925 return;
900 926 clear_lists();
901 927 }
902 928
903 929 static void register_lock(int index)
904 930 {
905 931 struct lock_info *lock = &lock_table[index];
906 932 void *idx = INT_PTR(index);
907 933
908 934 if (lock->return_type == ret_non_zero) {
909 - return_implies_state(lock->function, valid_ptr_min, valid_ptr_max, &match_lock_held, idx);
935 + return_implies_state(lock->function, 1, INT_MAX, &match_lock_held, idx);
910 936 return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
911 937 } else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
912 938 add_function_assign_hook(lock->function, &match_returns_locked, idx);
913 939 } else if (lock->return_type == ret_any) {
914 940 add_function_hook(lock->function, &match_lock_unlock, idx);
915 941 } else if (lock->return_type == ret_zero) {
916 942 return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
917 943 return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
944 + } else if (lock->return_type == ret_one) {
945 + return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
946 + return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
918 947 }
919 948 }
920 949
921 950 static void load_table(struct lock_info *_lock_table, int size)
922 951 {
923 952 int i;
924 953
925 954 lock_table = _lock_table;
926 955
927 956 for (i = 0; i < size; i++) {
928 957 if (lock_table[i].action == LOCK)
929 958 register_lock(i);
930 959 else
931 960 add_function_hook(lock_table[i].function, &match_lock_unlock, INT_PTR(i));
932 961 }
933 962 }
934 963
935 964 /* print_held_locks() is used in check_call_tree.c */
936 965 void print_held_locks(void)
937 966 {
938 967 struct stree *stree;
939 968 struct sm_state *sm;
940 969 int i = 0;
941 970
942 971 stree = __get_cur_stree();
943 972 FOR_EACH_MY_SM(my_id, stree, sm) {
944 973 if (sm->state != &locked)
945 974 continue;
946 975 if (i++)
947 976 sm_printf(" ");
948 977 sm_printf("'%s'", sm->name);
949 978 } END_FOR_EACH_SM(sm);
950 979 }
951 980
952 981 void check_locking(int id)
953 982 {
954 983 my_id = id;
955 984
956 985 if (option_project == PROJ_WINE)
957 986 load_table(wine_lock_table, ARRAY_SIZE(wine_lock_table));
958 987 else if (option_project == PROJ_KERNEL)
959 988 load_table(kernel_lock_table, ARRAY_SIZE(kernel_lock_table));
960 989 else
961 990 return;
962 991
963 992 add_unmatched_state_hook(my_id, &unmatched_state);
964 993 add_pre_merge_hook(my_id, &pre_merge_hook);
965 994 add_split_return_callback(match_return);
966 995 add_hook(&match_func_end, END_FUNC_HOOK);
967 996 add_hook(&match_after_func, AFTER_FUNC_HOOK);
968 997
969 998 }
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX