Improve how the debug info for merging states gets printed out.
[smatch.git] / smatch_flow.c
blob12f0b9ce473c47344817b7cedef52ef76fdc62bf
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 static void special_kernel_macros(struct expression *expr)
94 #ifdef KERNEL
95 struct expression *tmp;
97 tmp = first_ptr_list((struct ptr_list *) expr->args);
98 if (tmp->op == '!' && tmp->unop->op == '!'
99 && tmp->unop->unop->op == '(') {
100 split_conditions(tmp->unop->unop->unop);
101 } else {
102 __pass_to_client(expr, CONDITION_HOOK);
103 split_expr(expr);
104 return;
107 #endif
110 static int is_zero(struct expression *expr)
112 if (expr->type == EXPR_VALUE && expr->value == 0)
113 return 1;
114 if (expr->op == '(')
115 return is_zero(expr->unop);
116 if (expr->type == EXPR_CAST)
117 return is_zero(expr->cast_expression);
118 return 0;
121 static int handle_zero_comparisons(struct expression *expr)
123 struct expression *tmp = NULL;
125 // if left is zero or right is zero
126 if (is_zero(expr->left))
127 tmp = expr->right;
128 else if (is_zero(expr->right))
129 tmp = expr->left;
130 else
131 return 0;
133 // "if (foo != 0)" is the same as "if (foo)"
134 if (expr->op == SPECIAL_NOTEQUAL) {
135 split_conditions(tmp);
136 return 1;
139 // "if (foo == 0)" is the same as "if (!foo)"
140 if (expr->op == SPECIAL_EQUAL) {
141 __negate = (__negate + 1)%2;
142 split_conditions(tmp);
143 __negate = (__negate + 1)%2;
144 return 1;
147 return 0;
150 void split_conditions(struct expression *expr)
153 * If you have if ((a || a = foo()), we know a is
154 * non-null on the true state because 'a' is checked in both and
155 * groups. __ors_reached helps with that. Unfortunately
156 * smatch doesn't handle stuff like if (a && a = foo())
157 * because it never occured to me that people would do that...
160 static int __ors_reached;
162 SM_DEBUG("%d in split_conditions type=%d\n", get_lineno(), expr->type);
164 if (expr->type == EXPR_COMPARE)
165 if (handle_zero_comparisons(expr))
166 return;
168 if (expr->type == EXPR_LOGICAL) {
169 unsigned int path_orig;
171 inc_ands_ors(expr);
172 path_orig = split_path_id();
173 __split_false_states_mini();
175 split_conditions(expr->left);
177 if (is_logical_and(expr)) {
178 split_path_id();
179 __pop_false_states_mini();
180 split_conditions(expr->right);
181 } else if (is_logical_or(expr)) {
182 if (!__ors_reached) {
183 __ors_reached = 1;
184 __first_and_clump();
185 } else {
186 __merge_and_clump();
188 split_path_id();
189 __use_false_states_mini();
190 split_conditions(expr->right);
192 dec_ands_ors(expr);
194 if (__ands + __ors == 0) {
195 __merge_and_clump();
196 __use_and_clumps();
197 __ors_reached = 0;
200 restore_path_id(path_orig);
201 return;
202 } else if (expr->type == EXPR_PREOP && expr->op == '!') {
203 __negate = (__negate + 1)%2;
204 split_conditions(expr->unop);
205 __negate = (__negate + 1)%2;
206 return;
207 } else if (expr->type == EXPR_PREOP && expr->op == '(') {
208 split_conditions(expr->unop);
209 } else if (expr->type == EXPR_CALL) {
211 if (expr->fn->type != EXPR_SYMBOL ||
212 strcmp("__builtin_expect", expr->fn->symbol_name->name)) {
213 __pass_to_client(expr, CONDITION_HOOK);
214 split_expr(expr);
215 return;
217 special_kernel_macros(expr);
218 } else {
219 __pass_to_client(expr, CONDITION_HOOK);
220 split_expr(expr);
224 static void split_whole_condition(struct expression *expr)
227 split_conditions(expr);
228 SM_DEBUG("%d __ands = %d __ors = %d __negate = %d\n", get_lineno(),
229 __ands, __ors, __negate);
232 static void split_expr(struct expression *expr)
234 if (!expr)
235 return;
237 __smatch_lineno = expr->pos.line;
238 __pass_to_client(expr, EXPR_HOOK);
240 // printf("%d Debug expr_type %d\n", get_lineno(), expr->type);
242 switch (expr->type) {
243 case EXPR_PREOP:
244 case EXPR_POSTOP:
245 if (expr->op == '*')
246 __pass_to_client(expr, DEREF_HOOK);
247 split_expr(expr->unop);
248 return;
249 case EXPR_STATEMENT:
250 split_statements(expr->statement);
251 return;
252 case EXPR_BINOP:
253 case EXPR_COMMA:
254 case EXPR_COMPARE:
255 case EXPR_LOGICAL:
256 case EXPR_ASSIGNMENT:
257 if (expr->type == EXPR_ASSIGNMENT)
258 __pass_to_client(expr, ASSIGNMENT_HOOK);
259 split_expr(expr->left);
260 split_expr(expr->right);
261 if (expr->type == EXPR_ASSIGNMENT)
262 __pass_to_client(expr, ASSIGNMENT_AFTER_HOOK);
263 return;
264 case EXPR_DEREF:
265 __pass_to_client(expr, DEREF_HOOK);
266 split_expr(expr->deref);
267 return;
268 case EXPR_SLICE:
269 split_expr(expr->base);
270 return;
271 case EXPR_CAST:
272 case EXPR_SIZEOF:
273 split_expr(expr->cast_expression);
274 return;
275 case EXPR_CONDITIONAL:
276 case EXPR_SELECT:
277 __split_true_false_paths();
278 __pass_to_client(expr->conditional, WHOLE_CONDITION_HOOK);
279 split_whole_condition(expr->conditional);
280 __use_true_states();
281 split_expr(expr->cond_true);
282 __use_false_states();
283 split_expr(expr->cond_false);
284 __merge_true_states();
285 return;
286 case EXPR_CALL:
287 __pass_to_client(expr, FUNCTION_CALL_HOOK);
288 split_expr(expr->fn);
289 split_expr_list(expr->args);
290 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
291 #ifdef KERNEL
292 if (expr->fn->type == EXPR_SYMBOL &&
293 !strcmp(expr->fn->symbol_name->name, "panic"))
294 nullify_path();
295 #endif
296 return;
297 case EXPR_INITIALIZER:
298 split_expr_list(expr->expr_list);
299 return;
300 case EXPR_IDENTIFIER:
301 split_expr(expr->ident_expression);
302 return;
303 case EXPR_INDEX:
304 split_expr(expr->idx_expression);
305 return;
306 case EXPR_POS:
307 split_expr(expr->init_expr);
308 return;
309 default:
310 return;
314 static int is_forever_loop(struct statement *stmt)
317 struct expression *expr;
319 expr = stmt->iterator_pre_condition;
320 if (!expr)
321 expr = stmt->iterator_post_condition;
322 if (!expr) {
323 // this is a for(;;) loop...
324 return 1;
327 if (expr->type == EXPR_VALUE && expr->value == 1) {
328 return 1;
331 return 0;
335 * Pre Loops are while and for loops.
338 static void handle_pre_loop(struct statement *stmt)
340 unsigned int path_orig;
342 split_statements(stmt->iterator_pre_statement);
344 __split_true_false_paths();
345 __push_continues();
346 __push_breaks();
347 if (stmt->iterator_pre_condition) {
348 __pass_to_client(stmt->iterator_pre_condition, WHOLE_CONDITION_HOOK);
349 split_whole_condition(stmt->iterator_pre_condition);
351 path_orig = split_path_id();
352 __use_true_states();
354 split_statements(stmt->iterator_statement);
355 split_statements(stmt->iterator_post_statement);
356 if (is_forever_loop(stmt)) {
357 __pop_continues();
358 __pop_false_states();
359 nullify_path();
360 } else {
361 __merge_false_states();
362 __merge_continues();
364 __merge_breaks();
365 restore_path_id(path_orig);
369 * Post loops are do {} while();
371 static void handle_post_loop(struct statement *stmt)
373 __push_continues();
374 __push_breaks();
375 split_statements(stmt->iterator_statement);
377 __split_true_false_paths();
378 __pass_to_client(stmt->iterator_post_condition, WHOLE_CONDITION_HOOK);
379 split_whole_condition(stmt->iterator_post_condition);
380 /* It would prossibly be cleaner to make this all one function */
381 __use_true_states();
382 __use_false_states();
383 __pop_true_states();
385 if (is_forever_loop(stmt)) {
386 __pop_continues();
387 nullify_path();
388 } else {
389 __merge_continues();
391 __merge_breaks();
394 static void split_statements(struct statement *stmt)
396 unsigned int path_orig;
398 if (!stmt)
399 return;
401 __smatch_lineno = stmt->pos.line;
402 __pass_to_client(stmt, STMT_HOOK);
404 switch (stmt->type) {
405 case STMT_DECLARATION:
406 __pass_declarations_to_client(stmt->declaration);
407 split_symlist(stmt->declaration);
408 return;
409 case STMT_RETURN:
410 __pass_to_client(stmt, RETURN_HOOK);
411 split_expr(stmt->ret_value);
412 nullify_path();
413 return;
414 case STMT_EXPRESSION:
415 split_expr(stmt->expression);
416 return;
417 case STMT_COMPOUND: {
418 struct statement *s;
419 FOR_EACH_PTR(stmt->stmts, s) {
420 split_statements(s);
421 } END_FOR_EACH_PTR(s);
422 return;
424 case STMT_IF:
425 __split_true_false_paths();
426 __pass_to_client(stmt->if_conditional, WHOLE_CONDITION_HOOK);
427 split_whole_condition(stmt->if_conditional);
428 path_orig = split_path_id();
429 __use_true_states();
430 split_statements(stmt->if_true);
431 split_path_id();
432 __use_false_states();
433 split_statements(stmt->if_false);
434 __merge_true_states();
435 restore_path_id(path_orig);
436 return;
437 case STMT_ITERATOR:
438 if (stmt->iterator_pre_condition)
439 handle_pre_loop(stmt);
440 else if (stmt->iterator_post_condition)
441 handle_post_loop(stmt);
442 else {
443 // these are for(;;) type loops.
444 handle_pre_loop(stmt);
446 return;
447 case STMT_SWITCH:
448 split_expr(stmt->switch_expression);
449 __save_switch_states();
450 __push_default();
451 __push_breaks();
452 nullify_path();
453 path_orig = get_path_id();
454 split_statements(stmt->switch_statement);
455 if (!__pop_default())
456 __merge_switches();
457 __pop_switches();
458 __merge_breaks();
459 restore_path_id(path_orig);
460 return;
461 case STMT_CASE:
462 split_path_id();
463 __merge_switches();
464 if (!stmt->case_expression)
465 __set_default();
466 split_expr(stmt->case_expression);
467 split_expr(stmt->case_to);
468 split_statements(stmt->case_statement);
469 return;
470 case STMT_LABEL:
471 if (stmt->label &&
472 stmt->label->type == SYM_LABEL &&
473 stmt->label->ident) {
474 __merge_gotos(stmt->label->ident->name);
476 split_statements(stmt->label_statement);
477 return;
478 case STMT_GOTO:
479 split_expr(stmt->goto_expression);
480 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
481 if (!strcmp(stmt->goto_label->ident->name, "break")) {
482 __process_breaks();
483 } else if (!strcmp(stmt->goto_label->ident->name,
484 "continue")) {
485 __process_continues();
487 } else if (stmt->goto_label &&
488 stmt->goto_label->type == SYM_LABEL &&
489 stmt->goto_label->ident) {
490 __save_gotos(stmt->goto_label->ident->name);
492 nullify_path();
493 return;
494 case STMT_NONE:
495 return;
496 case STMT_ASM:
497 split_expr(stmt->asm_string);
498 //split_expr(stmt->asm_outputs);
499 //split_expr(stmt->asm_inputs);
500 //split_expr(stmt->asm_clobbers);
501 return;
502 case STMT_CONTEXT:
503 return;
504 case STMT_RANGE:
505 split_expr(stmt->range_expression);
506 split_expr(stmt->range_low);
507 split_expr(stmt->range_high);
508 return;
512 static void split_expr_list(struct expression_list *expr_list)
514 struct expression *expr;
515 FOR_EACH_PTR(expr_list, expr) {
516 split_expr(expr);
517 } END_FOR_EACH_PTR(expr);
521 static void split_sym(struct symbol *sym)
523 if (!sym)
524 return;
525 if (!(sym->namespace & NS_SYMBOL))
526 return;
528 __pass_to_client(sym, SYM_HOOK);
529 split_statements(sym->stmt);
530 split_expr(sym->array_size);
531 split_symlist(sym->arguments);
532 split_symlist(sym->symbol_list);
533 split_statements(sym->inline_stmt);
534 split_symlist(sym->inline_symbol_list);
535 split_expr(sym->initializer);
538 static void split_symlist(struct symbol_list *sym_list)
540 struct symbol *sym;
542 FOR_EACH_PTR(sym_list, sym) {
543 split_sym(sym);
544 } END_FOR_EACH_PTR(sym);
547 static void split_functions(struct symbol_list *sym_list)
549 struct symbol *sym;
551 FOR_EACH_PTR(sym_list, sym) {
552 struct symbol *base_type;
553 base_type = get_base_type(sym);
554 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
555 if (base_type->stmt)
556 line_func_start = base_type->stmt->pos.line;
557 if (sym->ident)
558 cur_func = sym->ident->name;
559 __smatch_lineno = sym->pos.line;
560 __pass_to_client(sym, FUNC_DEF_HOOK);
561 split_statements(base_type->stmt);
562 __pass_to_client(sym, END_FUNC_HOOK);
563 cur_func = NULL;
564 line_func_start = 0;
565 clear_all_states();
567 } else {
568 __pass_to_client(sym, BASE_HOOK);
570 } END_FOR_EACH_PTR(sym);
573 void smatch (int argc, char **argv)
576 struct string_list *filelist = NULL;
577 struct symbol_list *sym_list;
579 if (argc < 2) {
580 printf("Usage: smatch <filename.c>\n");
581 exit(1);
583 sparse_initialize(argc, argv, &filelist);
584 FOR_EACH_PTR_NOTAG(filelist, filename) {
585 sym_list = __sparse(filename);
586 split_functions(sym_list);
587 } END_FOR_EACH_PTR_NOTAG(filename);