The sparse_initialize() function now takes a filelist
[smatch.git] / smatch_flow.c
blobc984f61e7e1d085f2df87ef3f88a8a407ce1d4d8
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 __pass_to_client(stmt, STMT_HOOK);
330 switch (stmt->type) {
331 case STMT_DECLARATION:
332 __pass_declarations_to_client(stmt->declaration);
333 split_symlist(stmt->declaration);
334 return;
335 case STMT_RETURN:
336 __pass_to_client(stmt, RETURN_HOOK);
337 split_expr(stmt->ret_value);
338 nullify_path();
339 return;
340 case STMT_EXPRESSION:
341 split_expr(stmt->expression);
342 return;
343 case STMT_COMPOUND: {
344 struct statement *s;
345 FOR_EACH_PTR(stmt->stmts, s) {
346 split_statements(s);
347 } END_FOR_EACH_PTR(s);
348 return;
350 case STMT_IF:
351 __split_true_false_paths();
352 __pass_to_client(stmt->if_conditional, WHOLE_CONDITION_HOOK);
353 split_conditions(stmt->if_conditional);
354 path_orig = split_path_id();
355 __use_true_states();
356 split_statements(stmt->if_true);
357 split_path_id();
358 __use_false_states();
359 split_statements(stmt->if_false);
360 __merge_true_states();
361 restore_path_id(path_orig);
362 return;
363 case STMT_ITERATOR:
364 if (stmt->iterator_pre_condition)
365 handle_pre_loop(stmt);
366 else if (stmt->iterator_post_condition)
367 handle_post_loop(stmt);
368 return;
369 case STMT_SWITCH:
370 split_expr(stmt->switch_expression);
371 __save_switch_states();
372 __push_default();
373 __push_breaks();
374 nullify_path();
375 path_orig = get_path_id();
376 split_statements(stmt->switch_statement);
377 if (!__pop_default())
378 __merge_switches();
379 __pop_switches();
380 __merge_breaks();
381 restore_path_id(path_orig);
382 return;
383 case STMT_CASE:
384 split_path_id();
385 __merge_switches();
386 if (!stmt->case_expression)
387 __set_default();
388 split_expr(stmt->case_expression);
389 split_expr(stmt->case_to);
390 split_statements(stmt->case_statement);
391 return;
392 case STMT_LABEL:
393 if (stmt->label &&
394 stmt->label->type == SYM_LABEL &&
395 stmt->label->ident) {
396 __merge_gotos(stmt->label->ident->name);
398 split_statements(stmt->label_statement);
399 return;
400 case STMT_GOTO:
401 split_expr(stmt->goto_expression);
402 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
403 if (!strcmp(stmt->goto_label->ident->name, "break")) {
404 __process_breaks();
405 } else if (!strcmp(stmt->goto_label->ident->name,
406 "continue")) {
407 __process_continues();
409 } else if (stmt->goto_label &&
410 stmt->goto_label->type == SYM_LABEL &&
411 stmt->goto_label->ident) {
412 __save_gotos(stmt->goto_label->ident->name);
414 nullify_path();
415 return;
416 case STMT_NONE:
417 return;
418 case STMT_ASM:
419 split_expr(stmt->asm_string);
420 //split_expr(stmt->asm_outputs);
421 //split_expr(stmt->asm_inputs);
422 //split_expr(stmt->asm_clobbers);
423 return;
424 case STMT_CONTEXT:
425 return;
426 case STMT_RANGE:
427 split_expr(stmt->range_expression);
428 split_expr(stmt->range_low);
429 split_expr(stmt->range_high);
430 return;
434 static void split_expr_list(struct expression_list *expr_list)
436 struct expression *expr;
437 FOR_EACH_PTR(expr_list, expr) {
438 split_expr(expr);
439 } END_FOR_EACH_PTR(expr);
443 static void split_sym(struct symbol *sym)
445 if (!sym)
446 return;
447 if (!(sym->namespace & NS_SYMBOL))
448 return;
450 __pass_to_client(sym, SYM_HOOK);
451 split_statements(sym->stmt);
452 split_expr(sym->array_size);
453 split_symlist(sym->arguments);
454 split_symlist(sym->symbol_list);
455 split_statements(sym->inline_stmt);
456 split_symlist(sym->inline_symbol_list);
457 split_expr(sym->initializer);
460 static void split_symlist(struct symbol_list *sym_list)
462 struct symbol *sym;
464 FOR_EACH_PTR(sym_list, sym) {
465 split_sym(sym);
466 } END_FOR_EACH_PTR(sym);
469 static void split_functions(struct symbol_list *sym_list)
471 struct symbol *sym;
473 FOR_EACH_PTR(sym_list, sym) {
474 struct symbol *base_type;
475 base_type = get_base_type(sym);
476 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
477 if (base_type->stmt)
478 line_func_start = base_type->stmt->pos.line;
479 if (sym->ident)
480 cur_func = sym->ident->name;
481 __pass_to_client(sym, FUNC_DEF_HOOK);
482 split_statements(base_type->stmt);
483 __pass_to_client(sym, END_FUNC_HOOK);
484 cur_func = NULL;
485 line_func_start = 0;
486 clear_all_states();
488 } else {
489 __pass_to_client(sym, BASE_HOOK);
491 } END_FOR_EACH_PTR(sym);
494 void smatch (int argc, char **argv)
497 struct string_list *filelist = NULL;
498 struct symbol_list *sym_list;
500 if (argc < 2) {
501 printf("Usage: smatch <filename.c>\n");
502 exit(1);
504 sparse_initialize(argc, argv, &filelist);
505 FOR_EACH_PTR_NOTAG(filelist, filename) {
506 sym_list = __sparse(filename);
507 split_functions(sym_list);
508 } END_FOR_EACH_PTR_NOTAG(filename);