Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/check_double_checking.c
+++ new/usr/src/tools/smatch/src/check_double_checking.c
1 1 /*
2 2 * Copyright (C) 2014 Oracle.
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 #define _GNU_SOURCE
19 19 #include <string.h>
20 20 #include "smatch.h"
21 21 #include "smatch_slist.h"
22 22
23 23 static int my_id;
24 24
25 25 STATE(checked);
26 26 STATE(modified);
27 27
28 28 struct stree *to_check;
29 29
30 30 static struct statement *get_cur_stmt(void)
31 31 {
32 32 return last_ptr_list((struct ptr_list *)big_statement_stack);
33 33 }
34 34
35 35 static void set_modified(struct sm_state *sm, struct expression *mod_expr)
36 36 {
37 37 set_state(my_id, sm->name, sm->sym, &modified);
38 38 }
39 39
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
40 40 static struct expression *strip_condition(struct expression *expr)
41 41 {
42 42 expr = strip_expr(expr);
43 43
44 44 if (expr->type == EXPR_PREOP && expr->op == '!')
45 45 return strip_condition(expr->unop);
46 46
47 47 if (expr->type == EXPR_COMPARE &&
48 48 (expr->op == SPECIAL_EQUAL ||
49 49 expr->op == SPECIAL_NOTEQUAL)) {
50 - if (is_zero(expr->left))
50 + if (expr_is_zero(expr->left))
51 51 return strip_condition(expr->right);
52 - if (is_zero(expr->right))
52 + if (expr_is_zero(expr->right))
53 53 return strip_condition(expr->left);
54 54 }
55 55
56 56 return expr;
57 57 }
58 58
59 59 static int conditions_match(struct expression *cond, struct expression *prev)
60 60 {
61 61 prev = strip_condition(prev);
62 62
63 63 if (prev == cond)
64 64 return 1;
65 65
66 66 if (prev->type == EXPR_LOGICAL) {
67 67 if (conditions_match(cond, prev->left) ||
68 68 conditions_match(cond, prev->right))
69 69 return 1;
70 70 }
71 71
72 72 return 0;
73 73 }
74 74
75 75 /*
76 76 * People like to do "if (foo) { ... } else if (!foo) { ... }". Don't
77 77 * complain when they do that even though it is nonsense.
78 78 */
79 79 static int is_obvious_else(struct expression *cond)
80 80 {
81 81 struct statement *parent;
82 82 struct expression *prev;
83 83
84 84 if (!get_cur_stmt())
85 85 return 0;
86 86 parent = get_cur_stmt()->parent;
87 87 if (!parent)
88 88 return 0;
89 89
90 90 if (parent->type != STMT_IF)
91 91 return 0;
92 92
93 93 if (!parent->if_false)
94 94 return 0;
95 95 if (parent->if_false != get_cur_stmt())
96 96 return 0;
97 97
98 98 prev = strip_condition(parent->if_conditional);
99 99
100 100 return conditions_match(cond, prev);
101 101 }
102 102
103 103 static int name_means_synchronize(const char *name)
104 104 {
105 105 if (!name)
106 106 return 0;
107 107
108 108 if (strcasestr(name, "wait"))
109 109 return 1;
110 110 if (strcasestr(name, "down"))
111 111 return 1;
112 112 if (strcasestr(name, "lock") && !strcasestr(name, "unlock"))
113 113 return 1;
114 114 if (strcasestr(name, "delay"))
115 115 return 1;
116 116 if (strcasestr(name, "schedule"))
117 117 return 1;
118 118 if (strcmp(name, "smp_rmb") == 0)
119 119 return 1;
120 120 if (strcmp(name, "mb") == 0)
121 121 return 1;
122 122 if (strcmp(name, "barrier") == 0)
123 123 return 1;
↓ open down ↓ |
61 lines elided |
↑ open up ↑ |
124 124 return 0;
125 125 }
126 126
127 127 static int previous_statement_was_synchronize(void)
128 128 {
129 129 struct statement *stmt;
130 130 struct position pos;
131 131 struct position prev_pos;
132 132 char *ident;
133 133
134 + if (!__cur_stmt)
135 + return 0;
136 +
134 137 if (__prev_stmt) {
135 138 prev_pos = __prev_stmt->pos;
136 139 prev_pos.line -= 3;
137 140 } else {
138 141 prev_pos = __cur_stmt->pos;
139 142 prev_pos.line -= 5;
140 143 }
141 144
142 145 FOR_EACH_PTR_REVERSE(big_statement_stack, stmt) {
143 146 if (stmt->pos.line < prev_pos.line)
144 147 return 0;
145 148 pos = stmt->pos;
146 149 ident = get_macro_name(pos);
147 150 if (name_means_synchronize(ident))
148 151 return 1;
149 152 ident = pos_ident(pos);
150 153 if (!ident)
151 154 continue;
152 155 if (strcmp(ident, "if") == 0) {
153 156 pos.pos += 4;
154 157 ident = pos_ident(pos);
155 158 if (!ident)
156 159 continue;
157 160 }
158 161 if (name_means_synchronize(ident))
159 162 return 1;
160 163 } END_FOR_EACH_PTR_REVERSE(stmt);
161 164 return 0;
162 165 }
163 166
164 167 static void match_condition(struct expression *expr)
165 168 {
166 169 struct smatch_state *state;
167 170 sval_t dummy;
168 171 char *name;
169 172
170 173 if (inside_loop())
171 174 return;
172 175
173 176 if (get_value(expr, &dummy))
174 177 return;
175 178
176 179 if (get_macro_name(expr->pos))
177 180 return;
178 181
179 182 state = get_stored_condition(expr);
180 183 if (!state || !state->data)
181 184 return;
182 185 if (get_macro_name(((struct expression *)state->data)->pos))
183 186 return;
184 187
185 188 /*
186 189 * we allow double checking for NULL because people do this all the time
187 190 * and trying to stop them is a losers' battle.
188 191 */
189 192 if (is_pointer(expr) && implied_condition_true(expr))
190 193 return;
191 194
192 195 if (definitely_inside_loop()) {
193 196 struct symbol *sym;
194 197
195 198 if (__inline_fn)
196 199 return;
197 200
198 201 name = expr_to_var_sym(expr, &sym);
199 202 if (!name)
200 203 return;
201 204 set_state_expr(my_id, expr, &checked);
202 205 set_state_stree(&to_check, my_id, name, sym, &checked);
203 206 free_string(name);
204 207 return;
205 208 }
206 209
207 210 if (is_obvious_else(state->data))
208 211 return;
209 212
210 213 /*
211 214 * It's common to test something, then take a lock and test if it is
212 215 * still true.
213 216 */
214 217 if (previous_statement_was_synchronize())
215 218 return;
216 219
217 220 name = expr_to_str(expr);
218 221 sm_warning("we tested '%s' before and it was '%s'", name, state->name);
219 222 free_string(name);
220 223 }
221 224
222 225 int get_check_line(struct sm_state *sm)
223 226 {
224 227 struct sm_state *tmp;
225 228
226 229 FOR_EACH_PTR(sm->possible, tmp) {
227 230 if (tmp->state == &checked)
228 231 return tmp->line;
229 232 } END_FOR_EACH_PTR(tmp);
230 233
231 234 return get_lineno();
232 235 }
233 236
234 237 static void after_loop(struct statement *stmt)
235 238 {
236 239 struct sm_state *check, *sm;
237 240
238 241 if (!stmt || stmt->type != STMT_ITERATOR)
239 242 return;
240 243 if (definitely_inside_loop())
241 244 return;
242 245 if (__inline_fn)
243 246 return;
244 247
245 248 FOR_EACH_SM(to_check, check) {
246 249 continue;
247 250 sm = get_sm_state(my_id, check->name, check->sym);
248 251 continue;
249 252 if (!sm)
250 253 continue;
251 254 if (slist_has_state(sm->possible, &modified))
252 255 continue;
253 256
254 257 sm_printf("%s:%d %s() ", get_filename(), get_check_line(sm), get_function());
255 258 sm_printf("warn: we tested '%s' already\n", check->name);
256 259 } END_FOR_EACH_SM(check);
257 260
258 261 free_stree(&to_check);
259 262 }
260 263
261 264 static void match_func_end(struct symbol *sym)
262 265 {
263 266 if (__inline_fn)
264 267 return;
265 268 if (to_check)
266 269 sm_msg("debug: odd... found an function without an end.");
267 270 free_stree(&to_check);
268 271 }
269 272
270 273 void check_double_checking(int id)
271 274 {
272 275 my_id = id;
273 276
274 277 if (!option_spammy)
275 278 return;
276 279
277 280 add_hook(&match_condition, CONDITION_HOOK);
278 281 add_modification_hook(my_id, &set_modified);
279 282 add_hook(after_loop, STMT_HOOK_AFTER);
280 283 add_hook(&match_func_end, AFTER_FUNC_HOOK);
281 284 }
↓ open down ↓ |
138 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX