If you have something like
[smatch.git] / smatch_flow.c
blob4a85b0fae8432db1399375ca02e634860939ba6a
1 /*
2 * sparse/check_string_ret.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdio.h>
11 #include "token.h"
12 #include "smatch.h"
14 #define KERNEL
16 int __smatch_lineno = 0;
17 int __negate = 0;
18 int __ors = 0;
19 int __ands = 0;
21 static char *filename;
22 static char *cur_func;
23 static int line_func_start;
24 static unsigned int path_id = 0;
25 static unsigned int path_id_next = 1;
27 char *get_filename() { return filename; }
28 char *get_function() { return cur_func; }
29 int get_lineno() { return __smatch_lineno; }
30 int get_func_pos() { return __smatch_lineno - line_func_start; }
32 static void split_statements(struct statement *stmt);
33 static void split_symlist(struct symbol_list *sym_list);
34 static void split_expr_list(struct expression_list *expr_list);
35 static void split_expr(struct expression *expr);
37 unsigned int get_path_id()
39 return path_id;
42 static unsigned int split_path_id()
44 int tmp = path_id;
46 path_id = path_id_next++;
47 return tmp;
50 static void restore_path_id(int old_id)
52 path_id = old_id;
56 static int is_logical_and(struct expression *expr)
58 /* If you have if (!(a && b)) smatch translates that to
59 * if (!a || !b). Logically those are the same.
62 if ((!__negate && expr->op == SPECIAL_LOGICAL_AND) ||
63 (__negate && expr->op == SPECIAL_LOGICAL_OR))
64 return 1;
65 return 0;
68 static int is_logical_or(struct expression *expr)
70 if ((!__negate && expr->op == SPECIAL_LOGICAL_OR) ||
71 (__negate && expr->op == SPECIAL_LOGICAL_AND))
72 return 1;
73 return 0;
76 static void inc_ands_ors(struct expression *expr)
78 if (is_logical_and(expr))
79 __ands++;
80 else if (is_logical_or(expr))
81 __ors++;
84 static void dec_ands_ors(struct expression *expr)
86 if (is_logical_and(expr))
87 __ands--;
88 else if (is_logical_or(expr))
89 __ors--;
92 void split_conditions(struct expression *expr)
95 * If you have if ((a || a = foo()), we know a is
96 * non-null on the true state because 'a' is checked in both and
97 * groups. __ors_reached helps with that. Unfortunately
98 * smatch doesn't handle stuff like if (a && a = foo())
99 * because it never occured to me that people would do that...
102 static int __ors_reached;
104 if (expr->type == EXPR_LOGICAL) {
105 unsigned int path_orig;
107 inc_ands_ors(expr);
108 path_orig = split_path_id();
109 __split_false_states_mini();
111 split_conditions(expr->left);
113 if (is_logical_and(expr)) {
114 split_path_id();
115 __pop_false_states_mini();
116 split_conditions(expr->right);
117 } else if (is_logical_or(expr)) {
118 if (!__ors_reached) {
119 __ors_reached++;
120 __first_and_clump();
121 } else
122 __merge_and_clump();
124 split_path_id();
125 __use_false_states_mini();
126 split_conditions(expr->right);
128 dec_ands_ors(expr);
130 if (__ands + __ors == 0) {
131 __merge_and_clump();
132 __use_and_clumps();
133 __ors_reached = 0;
136 restore_path_id(path_orig);
137 return;
138 } else if (expr->type == EXPR_PREOP && expr->op == '!') {
139 __negate = (__negate + 1)%2;
140 split_conditions(expr->unop);
141 __negate = (__negate + 1)%2;
142 return;
143 } else if (expr->type == EXPR_PREOP && expr->op == '(') {
144 split_conditions(expr->unop);
145 #ifdef KERNEL
146 } else if (expr->type == EXPR_CALL) {
147 struct expression *arg;
149 if (expr->fn->type != EXPR_SYMBOL ||
150 strcmp("__builtin_expect", expr->fn->symbol_name->name)) {
151 __pass_to_client(expr, CONDITION_HOOK);
152 split_expr(expr);
153 return;
155 arg = first_ptr_list((struct ptr_list *) expr->args);
156 if (arg->op == '!' && arg->unop->op == '!'
157 && arg->unop->unop->op == '(')
158 split_conditions(arg->unop->unop->unop);
159 else {
160 __pass_to_client(expr, CONDITION_HOOK);
161 split_expr(expr);
162 return;
164 #endif
165 } else {
166 __pass_to_client(expr, CONDITION_HOOK);
167 split_expr(expr);
171 static void split_expr(struct expression *expr)
173 if (!expr)
174 return;
176 __smatch_lineno = expr->pos.line;
177 __pass_to_client(expr, EXPR_HOOK);
179 //printf("Debug expr_type %d\n", expr->type);
181 switch (expr->type) {
182 case EXPR_PREOP:
183 case EXPR_POSTOP:
184 if (expr->op == '*')
185 __pass_to_client(expr, DEREF_HOOK);
186 split_expr(expr->unop);
187 return;
188 case EXPR_STATEMENT:
189 split_statements(expr->statement);
190 return;
191 case EXPR_BINOP:
192 case EXPR_COMMA:
193 case EXPR_COMPARE:
194 case EXPR_LOGICAL:
195 case EXPR_ASSIGNMENT:
196 if (expr->type == EXPR_ASSIGNMENT)
197 __pass_to_client(expr, ASSIGNMENT_HOOK);
198 split_expr(expr->left);
199 split_expr(expr->right);
200 if (expr->type == EXPR_ASSIGNMENT)
201 __pass_to_client(expr, ASSIGNMENT_AFTER_HOOK);
202 return;
203 case EXPR_DEREF:
204 __pass_to_client(expr, DEREF_HOOK);
205 split_expr(expr->deref);
206 return;
207 case EXPR_SLICE:
208 split_expr(expr->base);
209 return;
210 case EXPR_CAST:
211 case EXPR_SIZEOF:
212 split_expr(expr->cast_expression);
213 return;
214 case EXPR_CONDITIONAL:
215 case EXPR_SELECT:
216 __split_true_false_paths();
217 __pass_to_client(expr->conditional, WHOLE_CONDITION_HOOK);
218 split_conditions(expr->conditional);
219 __use_true_states();
220 split_expr(expr->cond_true);
221 __use_false_states();
222 split_expr(expr->cond_false);
223 __merge_true_states();
224 return;
225 case EXPR_CALL:
226 __pass_to_client(expr, FUNCTION_CALL_HOOK);
227 split_expr(expr->fn);
228 split_expr_list(expr->args);
229 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
230 #ifdef KERNEL
231 if (expr->fn->type == EXPR_SYMBOL &&
232 !strcmp(expr->fn->symbol_name->name, "panic"))
233 nullify_path();
234 #endif
235 return;
236 case EXPR_INITIALIZER:
237 split_expr_list(expr->expr_list);
238 return;
239 case EXPR_IDENTIFIER:
240 split_expr(expr->ident_expression);
241 return;
242 case EXPR_INDEX:
243 split_expr(expr->idx_expression);
244 return;
245 case EXPR_POS:
246 split_expr(expr->init_expr);
247 return;
248 default:
249 return;
253 static int is_forever_loop(struct expression *expr)
256 if (expr->type == EXPR_VALUE && expr->value == 1) {
257 return 1;
259 return 0;
263 * Pre Loops are while and for loops.
266 static void handle_pre_loop(struct statement *stmt)
268 unsigned int path_orig;
270 split_statements(stmt->iterator_pre_statement);
272 __split_true_false_paths();
273 __push_continues();
274 __push_breaks();
275 __pass_to_client(stmt->iterator_pre_condition, WHOLE_CONDITION_HOOK);
276 split_conditions(stmt->iterator_pre_condition);
277 path_orig = split_path_id();
278 __use_true_states();
280 split_statements(stmt->iterator_statement);
281 split_statements(stmt->iterator_post_statement);
282 if (is_forever_loop(stmt->iterator_pre_condition)) {
283 __pop_continues();
284 __pop_false_states();
285 nullify_path();
286 } else {
287 nullify_path();
288 __merge_false_states();
289 __merge_continues();
291 __merge_breaks();
292 restore_path_id(path_orig);
296 * Post loops are do {} while();
298 static void handle_post_loop(struct statement *stmt)
300 __push_continues();
301 __push_breaks();
302 split_statements(stmt->iterator_statement);
304 __split_true_false_paths();
305 __pass_to_client(stmt->iterator_post_condition, WHOLE_CONDITION_HOOK);
306 split_conditions(stmt->iterator_post_condition);
307 /* It would prossibly be cleaner to make this all one function */
308 __use_true_states();
309 __use_false_states();
310 __pop_true_states();
312 if (is_forever_loop(stmt->iterator_post_condition)) {
313 __pop_continues();
314 nullify_path();
315 } else {
316 __merge_continues();
318 __merge_breaks();
321 static void split_statements(struct statement *stmt)
323 unsigned int path_orig;
325 if (!stmt)
326 return;
328 __smatch_lineno = stmt->pos.line;
329 __pass_to_client(stmt, STMT_HOOK);
331 switch (stmt->type) {
332 case STMT_DECLARATION:
333 __pass_declarations_to_client(stmt->declaration);
334 split_symlist(stmt->declaration);
335 return;
336 case STMT_RETURN:
337 __pass_to_client(stmt, RETURN_HOOK);
338 split_expr(stmt->ret_value);
339 nullify_path();
340 return;
341 case STMT_EXPRESSION:
342 split_expr(stmt->expression);
343 return;
344 case STMT_COMPOUND: {
345 struct statement *s;
346 FOR_EACH_PTR(stmt->stmts, s) {
347 split_statements(s);
348 } END_FOR_EACH_PTR(s);
349 return;
351 case STMT_IF:
352 __split_true_false_paths();
353 __pass_to_client(stmt->if_conditional, WHOLE_CONDITION_HOOK);
354 split_conditions(stmt->if_conditional);
355 path_orig = split_path_id();
356 __use_true_states();
357 split_statements(stmt->if_true);
358 split_path_id();
359 __use_false_states();
360 split_statements(stmt->if_false);
361 __merge_true_states();
362 restore_path_id(path_orig);
363 return;
364 case STMT_ITERATOR:
365 if (stmt->iterator_pre_condition)
366 handle_pre_loop(stmt);
367 else if (stmt->iterator_post_condition)
368 handle_post_loop(stmt);
369 return;
370 case STMT_SWITCH:
371 split_expr(stmt->switch_expression);
372 __save_switch_states();
373 __push_default();
374 __push_breaks();
375 nullify_path();
376 path_orig = get_path_id();
377 split_statements(stmt->switch_statement);
378 if (!__pop_default())
379 __merge_switches();
380 __pop_switches();
381 __merge_breaks();
382 restore_path_id(path_orig);
383 return;
384 case STMT_CASE:
385 split_path_id();
386 __merge_switches();
387 if (!stmt->case_expression)
388 __set_default();
389 split_expr(stmt->case_expression);
390 split_expr(stmt->case_to);
391 split_statements(stmt->case_statement);
392 return;
393 case STMT_LABEL:
394 if (stmt->label &&
395 stmt->label->type == SYM_LABEL &&
396 stmt->label->ident) {
397 __merge_gotos(stmt->label->ident->name);
399 split_statements(stmt->label_statement);
400 return;
401 case STMT_GOTO:
402 split_expr(stmt->goto_expression);
403 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
404 if (!strcmp(stmt->goto_label->ident->name, "break")) {
405 __process_breaks();
406 } else if (!strcmp(stmt->goto_label->ident->name,
407 "continue")) {
408 __process_continues();
410 } else if (stmt->goto_label &&
411 stmt->goto_label->type == SYM_LABEL &&
412 stmt->goto_label->ident) {
413 __save_gotos(stmt->goto_label->ident->name);
415 nullify_path();
416 return;
417 case STMT_NONE:
418 return;
419 case STMT_ASM:
420 split_expr(stmt->asm_string);
421 //split_expr(stmt->asm_outputs);
422 //split_expr(stmt->asm_inputs);
423 //split_expr(stmt->asm_clobbers);
424 return;
425 case STMT_CONTEXT:
426 return;
427 case STMT_RANGE:
428 split_expr(stmt->range_expression);
429 split_expr(stmt->range_low);
430 split_expr(stmt->range_high);
431 return;
435 static void split_expr_list(struct expression_list *expr_list)
437 struct expression *expr;
438 FOR_EACH_PTR(expr_list, expr) {
439 split_expr(expr);
440 } END_FOR_EACH_PTR(expr);
444 static void split_sym(struct symbol *sym)
446 if (!sym)
447 return;
448 if (!(sym->namespace & NS_SYMBOL))
449 return;
451 __pass_to_client(sym, SYM_HOOK);
452 split_statements(sym->stmt);
453 split_expr(sym->array_size);
454 split_symlist(sym->arguments);
455 split_symlist(sym->symbol_list);
456 split_statements(sym->inline_stmt);
457 split_symlist(sym->inline_symbol_list);
458 split_expr(sym->initializer);
461 static void split_symlist(struct symbol_list *sym_list)
463 struct symbol *sym;
465 FOR_EACH_PTR(sym_list, sym) {
466 split_sym(sym);
467 } END_FOR_EACH_PTR(sym);
470 static void split_functions(struct symbol_list *sym_list)
472 struct symbol *sym;
474 FOR_EACH_PTR(sym_list, sym) {
475 struct symbol *base_type;
476 base_type = get_base_type(sym);
477 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
478 if (base_type->stmt)
479 line_func_start = base_type->stmt->pos.line;
480 if (sym->ident)
481 cur_func = sym->ident->name;
482 __smatch_lineno = sym->pos.line;
483 __pass_to_client(sym, FUNC_DEF_HOOK);
484 split_statements(base_type->stmt);
485 __pass_to_client(sym, END_FUNC_HOOK);
486 cur_func = NULL;
487 line_func_start = 0;
488 clear_all_states();
490 } else {
491 __pass_to_client(sym, BASE_HOOK);
493 } END_FOR_EACH_PTR(sym);
496 void smatch (int argc, char **argv)
499 struct string_list *filelist = NULL;
500 struct symbol_list *sym_list;
502 if (argc < 2) {
503 printf("Usage: smatch <filename.c>\n");
504 exit(1);
506 sparse_initialize(argc, argv, &filelist);
507 FOR_EACH_PTR_NOTAG(filelist, filename) {
508 sym_list = __sparse(filename);
509 split_functions(sym_list);
510 } END_FOR_EACH_PTR_NOTAG(filename);