Handle while and for loops slightly better.
[smatch.git] / smatch_flow.c
blobf3ffa7fc01cde9de82cd0fc0082b497b46bf4b13
1 /*
2 * sparse/smatch_flow.c
4 * Copyright (C) 2006,2008 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 int __smatch_lineno = 0;
16 static char *filename;
17 static char *cur_func;
18 static int line_func_start;
20 char *get_filename() { return filename; }
21 char *get_function() { return cur_func; }
22 int get_lineno() { return __smatch_lineno; }
23 int get_func_pos() { return __smatch_lineno - line_func_start; }
25 static void split_statements(struct statement *stmt);
26 static void split_symlist(struct symbol_list *sym_list);
27 static void split_expr_list(struct expression_list *expr_list);
29 void __split_expr(struct expression *expr)
31 if (!expr)
32 return;
34 __smatch_lineno = expr->pos.line;
35 __pass_to_client(expr, EXPR_HOOK);
37 // printf("%d Debug expr_type %d\n", get_lineno(), expr->type);
39 switch (expr->type) {
40 case EXPR_PREOP:
41 case EXPR_POSTOP:
42 if (expr->op == '*')
43 __pass_to_client(expr, DEREF_HOOK);
44 __split_expr(expr->unop);
45 return;
46 case EXPR_STATEMENT:
47 split_statements(expr->statement);
48 return;
49 case EXPR_BINOP:
50 case EXPR_COMMA:
51 case EXPR_COMPARE:
52 case EXPR_LOGICAL:
53 case EXPR_ASSIGNMENT:
54 if (expr->type == EXPR_ASSIGNMENT)
55 __pass_to_client(expr, ASSIGNMENT_HOOK);
56 __split_expr(expr->left);
57 __split_expr(expr->right);
58 if (expr->type == EXPR_ASSIGNMENT)
59 __pass_to_client(expr, ASSIGNMENT_AFTER_HOOK);
60 return;
61 case EXPR_DEREF:
62 __pass_to_client(expr, DEREF_HOOK);
63 __split_expr(expr->deref);
64 return;
65 case EXPR_SLICE:
66 __split_expr(expr->base);
67 return;
68 case EXPR_CAST:
69 __split_expr(expr->cast_expression);
70 return;
71 case EXPR_SIZEOF:
72 /* there isn't anything to pass a client from inside a sizeof() */
73 return;
74 case EXPR_CONDITIONAL:
75 case EXPR_SELECT:
76 __split_true_false_paths();
77 __split_whole_condition(expr->conditional);
78 __use_true_states();
79 __split_expr(expr->cond_true);
80 __use_false_states();
81 __split_expr(expr->cond_false);
82 __merge_true_states();
83 return;
84 case EXPR_CALL:
85 __pass_to_client(expr, FUNCTION_CALL_HOOK);
86 __split_expr(expr->fn);
87 split_expr_list(expr->args);
88 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
89 #ifdef KERNEL
90 if (expr->fn->type == EXPR_SYMBOL &&
91 !strcmp(expr->fn->symbol_name->name, "panic"))
92 nullify_path();
93 #endif
94 return;
95 case EXPR_INITIALIZER:
96 split_expr_list(expr->expr_list);
97 return;
98 case EXPR_IDENTIFIER:
99 __split_expr(expr->ident_expression);
100 return;
101 case EXPR_INDEX:
102 __split_expr(expr->idx_expression);
103 return;
104 case EXPR_POS:
105 __split_expr(expr->init_expr);
106 return;
107 default:
108 return;
112 static int is_forever_loop(struct statement *stmt)
115 struct expression *expr;
117 expr = stmt->iterator_pre_condition;
118 if (!expr)
119 expr = stmt->iterator_post_condition;
120 if (!expr) {
121 // this is a for(;;) loop...
122 return 1;
125 if (expr->type == EXPR_VALUE && expr->value == 1) {
126 return 1;
129 return 0;
133 * Pre Loops are while and for loops.
136 static void handle_pre_loop(struct statement *stmt)
138 split_statements(stmt->iterator_pre_statement);
140 __split_true_false_paths();
141 __push_continues();
142 __push_breaks();
143 __prep_false_only_stack();
145 if (stmt->iterator_pre_condition) {
146 __split_whole_condition(stmt->iterator_pre_condition);
148 __use_true_states();
150 split_statements(stmt->iterator_statement);
151 split_statements(stmt->iterator_post_statement);
152 if (is_forever_loop(stmt)) {
153 __use_false_only_stack();
154 __pop_continues();
155 __pop_false_states();
156 nullify_path();
157 } else {
158 __merge_continues();
159 __merge_false_states();
160 __use_false_only_stack();
162 __merge_breaks();
166 * Post loops are do {} while();
168 static void handle_post_loop(struct statement *stmt)
170 __push_continues();
171 __push_breaks();
172 split_statements(stmt->iterator_statement);
174 __split_true_false_paths();
175 __split_whole_condition(stmt->iterator_post_condition);
176 /* It would prossibly be cleaner to make this all one function */
177 __use_true_states();
178 __use_false_states();
179 __pop_true_states();
181 if (is_forever_loop(stmt)) {
182 __pop_continues();
183 nullify_path();
184 } else {
185 __merge_continues();
187 __merge_breaks();
190 static void split_statements(struct statement *stmt)
192 if (!stmt)
193 return;
195 __smatch_lineno = stmt->pos.line;
196 __pass_to_client(stmt, STMT_HOOK);
198 switch (stmt->type) {
199 case STMT_DECLARATION:
200 __pass_declarations_to_client(stmt->declaration);
201 split_symlist(stmt->declaration);
202 return;
203 case STMT_RETURN:
204 __pass_to_client(stmt, RETURN_HOOK);
205 __split_expr(stmt->ret_value);
206 nullify_path();
207 return;
208 case STMT_EXPRESSION:
209 __split_expr(stmt->expression);
210 return;
211 case STMT_COMPOUND: {
212 struct statement *s;
213 FOR_EACH_PTR(stmt->stmts, s) {
214 split_statements(s);
215 } END_FOR_EACH_PTR(s);
216 return;
218 case STMT_IF:
219 __split_true_false_paths();
220 __split_whole_condition(stmt->if_conditional);
221 __use_true_states();
222 split_statements(stmt->if_true);
223 __use_false_states();
224 split_statements(stmt->if_false);
225 __merge_true_states();
226 return;
227 case STMT_ITERATOR:
228 if (stmt->iterator_pre_condition)
229 handle_pre_loop(stmt);
230 else if (stmt->iterator_post_condition)
231 handle_post_loop(stmt);
232 else {
233 // these are for(;;) type loops.
234 handle_pre_loop(stmt);
236 return;
237 case STMT_SWITCH:
238 __split_expr(stmt->switch_expression);
239 __save_switch_states();
240 __push_default();
241 __push_breaks();
242 nullify_path();
243 split_statements(stmt->switch_statement);
244 if (!__pop_default())
245 __merge_switches();
246 __pop_switches();
247 __merge_breaks();
248 return;
249 case STMT_CASE:
250 __merge_switches();
251 if (!stmt->case_expression)
252 __set_default();
253 __split_expr(stmt->case_expression);
254 __split_expr(stmt->case_to);
255 split_statements(stmt->case_statement);
256 return;
257 case STMT_LABEL:
258 if (stmt->label &&
259 stmt->label->type == SYM_LABEL &&
260 stmt->label->ident) {
261 __merge_gotos(stmt->label->ident->name);
263 split_statements(stmt->label_statement);
264 return;
265 case STMT_GOTO:
266 __split_expr(stmt->goto_expression);
267 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
268 if (!strcmp(stmt->goto_label->ident->name, "break")) {
269 __process_breaks();
270 } else if (!strcmp(stmt->goto_label->ident->name,
271 "continue")) {
272 __process_continues();
274 } else if (stmt->goto_label &&
275 stmt->goto_label->type == SYM_LABEL &&
276 stmt->goto_label->ident) {
277 __save_gotos(stmt->goto_label->ident->name);
279 nullify_path();
280 return;
281 case STMT_NONE:
282 return;
283 case STMT_ASM:
284 __split_expr(stmt->asm_string);
285 //__split_expr(stmt->asm_outputs);
286 //__split_expr(stmt->asm_inputs);
287 //__split_expr(stmt->asm_clobbers);
288 return;
289 case STMT_CONTEXT:
290 return;
291 case STMT_RANGE:
292 __split_expr(stmt->range_expression);
293 __split_expr(stmt->range_low);
294 __split_expr(stmt->range_high);
295 return;
299 static void split_expr_list(struct expression_list *expr_list)
301 struct expression *expr;
302 FOR_EACH_PTR(expr_list, expr) {
303 __split_expr(expr);
304 } END_FOR_EACH_PTR(expr);
308 static void split_sym(struct symbol *sym)
310 if (!sym)
311 return;
312 if (!(sym->namespace & NS_SYMBOL))
313 return;
315 __pass_to_client(sym, SYM_HOOK);
316 split_statements(sym->stmt);
317 __split_expr(sym->array_size);
318 split_symlist(sym->arguments);
319 split_symlist(sym->symbol_list);
320 split_statements(sym->inline_stmt);
321 split_symlist(sym->inline_symbol_list);
322 __split_expr(sym->initializer);
325 static void split_symlist(struct symbol_list *sym_list)
327 struct symbol *sym;
329 FOR_EACH_PTR(sym_list, sym) {
330 split_sym(sym);
331 } END_FOR_EACH_PTR(sym);
334 static void split_functions(struct symbol_list *sym_list)
336 struct symbol *sym;
338 FOR_EACH_PTR(sym_list, sym) {
339 struct symbol *base_type;
340 base_type = get_base_type(sym);
341 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
342 if (base_type->stmt)
343 line_func_start = base_type->stmt->pos.line;
344 if (sym->ident)
345 cur_func = sym->ident->name;
346 __smatch_lineno = sym->pos.line;
347 __pass_to_client(sym, FUNC_DEF_HOOK);
348 split_statements(base_type->stmt);
349 __pass_to_client(sym, END_FUNC_HOOK);
350 cur_func = NULL;
351 line_func_start = 0;
352 clear_all_states();
354 } else {
355 __pass_to_client(sym, BASE_HOOK);
357 } END_FOR_EACH_PTR(sym);
360 void smatch (int argc, char **argv)
363 struct string_list *filelist = NULL;
364 struct symbol_list *sym_list;
366 if (argc < 2) {
367 printf("Usage: smatch <filename.c>\n");
368 exit(1);
370 sparse_initialize(argc, argv, &filelist);
371 FOR_EACH_PTR_NOTAG(filelist, filename) {
372 sym_list = __sparse(filename);
373 split_functions(sym_list);
374 } END_FOR_EACH_PTR_NOTAG(filename);