Moved all the logic for handling conditions into a seperate file.
[smatch.git] / smatch_flow.c
blob44797e47b1d8748bdd81718deb0f37ceee9223c6
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;
19 static unsigned int path_id = 0;
20 static unsigned int path_id_next = 1;
22 char *get_filename() { return filename; }
23 char *get_function() { return cur_func; }
24 int get_lineno() { return __smatch_lineno; }
25 int get_func_pos() { return __smatch_lineno - line_func_start; }
27 static void split_statements(struct statement *stmt);
28 static void split_symlist(struct symbol_list *sym_list);
29 static void split_expr_list(struct expression_list *expr_list);
31 unsigned int get_path_id()
33 return path_id;
36 unsigned int __split_path_id()
38 int tmp = path_id;
40 path_id = path_id_next++;
41 return tmp;
44 void __restore_path_id(int old_id)
46 path_id = old_id;
51 void __split_expr(struct expression *expr)
53 if (!expr)
54 return;
56 __smatch_lineno = expr->pos.line;
57 __pass_to_client(expr, EXPR_HOOK);
59 // printf("%d Debug expr_type %d\n", get_lineno(), expr->type);
61 switch (expr->type) {
62 case EXPR_PREOP:
63 case EXPR_POSTOP:
64 if (expr->op == '*')
65 __pass_to_client(expr, DEREF_HOOK);
66 __split_expr(expr->unop);
67 return;
68 case EXPR_STATEMENT:
69 split_statements(expr->statement);
70 return;
71 case EXPR_BINOP:
72 case EXPR_COMMA:
73 case EXPR_COMPARE:
74 case EXPR_LOGICAL:
75 case EXPR_ASSIGNMENT:
76 if (expr->type == EXPR_ASSIGNMENT)
77 __pass_to_client(expr, ASSIGNMENT_HOOK);
78 __split_expr(expr->left);
79 __split_expr(expr->right);
80 if (expr->type == EXPR_ASSIGNMENT)
81 __pass_to_client(expr, ASSIGNMENT_AFTER_HOOK);
82 return;
83 case EXPR_DEREF:
84 __pass_to_client(expr, DEREF_HOOK);
85 __split_expr(expr->deref);
86 return;
87 case EXPR_SLICE:
88 __split_expr(expr->base);
89 return;
90 case EXPR_CAST:
91 __split_expr(expr->cast_expression);
92 return;
93 case EXPR_SIZEOF:
94 /* there isn't anything to pass a client from inside a sizeof() */
95 return;
96 case EXPR_CONDITIONAL:
97 case EXPR_SELECT:
98 __split_true_false_paths();
99 __pass_to_client(expr->conditional, WHOLE_CONDITION_HOOK);
100 __split_whole_condition(expr->conditional);
101 __use_true_states();
102 __split_expr(expr->cond_true);
103 __use_false_states();
104 __split_expr(expr->cond_false);
105 __merge_true_states();
106 return;
107 case EXPR_CALL:
108 __pass_to_client(expr, FUNCTION_CALL_HOOK);
109 __split_expr(expr->fn);
110 split_expr_list(expr->args);
111 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
112 #ifdef KERNEL
113 if (expr->fn->type == EXPR_SYMBOL &&
114 !strcmp(expr->fn->symbol_name->name, "panic"))
115 nullify_path();
116 #endif
117 return;
118 case EXPR_INITIALIZER:
119 split_expr_list(expr->expr_list);
120 return;
121 case EXPR_IDENTIFIER:
122 __split_expr(expr->ident_expression);
123 return;
124 case EXPR_INDEX:
125 __split_expr(expr->idx_expression);
126 return;
127 case EXPR_POS:
128 __split_expr(expr->init_expr);
129 return;
130 default:
131 return;
135 static int is_forever_loop(struct statement *stmt)
138 struct expression *expr;
140 expr = stmt->iterator_pre_condition;
141 if (!expr)
142 expr = stmt->iterator_post_condition;
143 if (!expr) {
144 // this is a for(;;) loop...
145 return 1;
148 if (expr->type == EXPR_VALUE && expr->value == 1) {
149 return 1;
152 return 0;
156 * Pre Loops are while and for loops.
159 static void handle_pre_loop(struct statement *stmt)
161 unsigned int path_orig;
163 split_statements(stmt->iterator_pre_statement);
165 __split_true_false_paths();
166 __push_continues();
167 __push_breaks();
168 if (stmt->iterator_pre_condition) {
169 __pass_to_client(stmt->iterator_pre_condition, WHOLE_CONDITION_HOOK);
170 __split_whole_condition(stmt->iterator_pre_condition);
172 path_orig = __split_path_id();
173 __use_true_states();
175 split_statements(stmt->iterator_statement);
176 split_statements(stmt->iterator_post_statement);
177 if (is_forever_loop(stmt)) {
178 __pop_continues();
179 __pop_false_states();
180 nullify_path();
181 } else {
182 __merge_false_states();
183 __merge_continues();
185 __merge_breaks();
186 __restore_path_id(path_orig);
190 * Post loops are do {} while();
192 static void handle_post_loop(struct statement *stmt)
194 __push_continues();
195 __push_breaks();
196 split_statements(stmt->iterator_statement);
198 __split_true_false_paths();
199 __pass_to_client(stmt->iterator_post_condition, WHOLE_CONDITION_HOOK);
200 __split_whole_condition(stmt->iterator_post_condition);
201 /* It would prossibly be cleaner to make this all one function */
202 __use_true_states();
203 __use_false_states();
204 __pop_true_states();
206 if (is_forever_loop(stmt)) {
207 __pop_continues();
208 nullify_path();
209 } else {
210 __merge_continues();
212 __merge_breaks();
215 static void split_statements(struct statement *stmt)
217 unsigned int path_orig;
219 if (!stmt)
220 return;
222 __smatch_lineno = stmt->pos.line;
223 __pass_to_client(stmt, STMT_HOOK);
225 switch (stmt->type) {
226 case STMT_DECLARATION:
227 __pass_declarations_to_client(stmt->declaration);
228 split_symlist(stmt->declaration);
229 return;
230 case STMT_RETURN:
231 __pass_to_client(stmt, RETURN_HOOK);
232 __split_expr(stmt->ret_value);
233 nullify_path();
234 return;
235 case STMT_EXPRESSION:
236 __split_expr(stmt->expression);
237 return;
238 case STMT_COMPOUND: {
239 struct statement *s;
240 FOR_EACH_PTR(stmt->stmts, s) {
241 split_statements(s);
242 } END_FOR_EACH_PTR(s);
243 return;
245 case STMT_IF:
246 __split_true_false_paths();
247 __pass_to_client(stmt->if_conditional, WHOLE_CONDITION_HOOK);
248 __split_whole_condition(stmt->if_conditional);
249 path_orig = __split_path_id();
250 __use_true_states();
251 split_statements(stmt->if_true);
252 __split_path_id();
253 __use_false_states();
254 split_statements(stmt->if_false);
255 __merge_true_states();
256 __restore_path_id(path_orig);
257 return;
258 case STMT_ITERATOR:
259 if (stmt->iterator_pre_condition)
260 handle_pre_loop(stmt);
261 else if (stmt->iterator_post_condition)
262 handle_post_loop(stmt);
263 else {
264 // these are for(;;) type loops.
265 handle_pre_loop(stmt);
267 return;
268 case STMT_SWITCH:
269 __split_expr(stmt->switch_expression);
270 __save_switch_states();
271 __push_default();
272 __push_breaks();
273 nullify_path();
274 path_orig = get_path_id();
275 split_statements(stmt->switch_statement);
276 if (!__pop_default())
277 __merge_switches();
278 __pop_switches();
279 __merge_breaks();
280 __restore_path_id(path_orig);
281 return;
282 case STMT_CASE:
283 __split_path_id();
284 __merge_switches();
285 if (!stmt->case_expression)
286 __set_default();
287 __split_expr(stmt->case_expression);
288 __split_expr(stmt->case_to);
289 split_statements(stmt->case_statement);
290 return;
291 case STMT_LABEL:
292 if (stmt->label &&
293 stmt->label->type == SYM_LABEL &&
294 stmt->label->ident) {
295 __merge_gotos(stmt->label->ident->name);
297 split_statements(stmt->label_statement);
298 return;
299 case STMT_GOTO:
300 __split_expr(stmt->goto_expression);
301 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
302 if (!strcmp(stmt->goto_label->ident->name, "break")) {
303 __process_breaks();
304 } else if (!strcmp(stmt->goto_label->ident->name,
305 "continue")) {
306 __process_continues();
308 } else if (stmt->goto_label &&
309 stmt->goto_label->type == SYM_LABEL &&
310 stmt->goto_label->ident) {
311 __save_gotos(stmt->goto_label->ident->name);
313 nullify_path();
314 return;
315 case STMT_NONE:
316 return;
317 case STMT_ASM:
318 __split_expr(stmt->asm_string);
319 //__split_expr(stmt->asm_outputs);
320 //__split_expr(stmt->asm_inputs);
321 //__split_expr(stmt->asm_clobbers);
322 return;
323 case STMT_CONTEXT:
324 return;
325 case STMT_RANGE:
326 __split_expr(stmt->range_expression);
327 __split_expr(stmt->range_low);
328 __split_expr(stmt->range_high);
329 return;
333 static void split_expr_list(struct expression_list *expr_list)
335 struct expression *expr;
336 FOR_EACH_PTR(expr_list, expr) {
337 __split_expr(expr);
338 } END_FOR_EACH_PTR(expr);
342 static void split_sym(struct symbol *sym)
344 if (!sym)
345 return;
346 if (!(sym->namespace & NS_SYMBOL))
347 return;
349 __pass_to_client(sym, SYM_HOOK);
350 split_statements(sym->stmt);
351 __split_expr(sym->array_size);
352 split_symlist(sym->arguments);
353 split_symlist(sym->symbol_list);
354 split_statements(sym->inline_stmt);
355 split_symlist(sym->inline_symbol_list);
356 __split_expr(sym->initializer);
359 static void split_symlist(struct symbol_list *sym_list)
361 struct symbol *sym;
363 FOR_EACH_PTR(sym_list, sym) {
364 split_sym(sym);
365 } END_FOR_EACH_PTR(sym);
368 static void split_functions(struct symbol_list *sym_list)
370 struct symbol *sym;
372 FOR_EACH_PTR(sym_list, sym) {
373 struct symbol *base_type;
374 base_type = get_base_type(sym);
375 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
376 if (base_type->stmt)
377 line_func_start = base_type->stmt->pos.line;
378 if (sym->ident)
379 cur_func = sym->ident->name;
380 __smatch_lineno = sym->pos.line;
381 __pass_to_client(sym, FUNC_DEF_HOOK);
382 split_statements(base_type->stmt);
383 __pass_to_client(sym, END_FUNC_HOOK);
384 cur_func = NULL;
385 line_func_start = 0;
386 clear_all_states();
388 } else {
389 __pass_to_client(sym, BASE_HOOK);
391 } END_FOR_EACH_PTR(sym);
394 void smatch (int argc, char **argv)
397 struct string_list *filelist = NULL;
398 struct symbol_list *sym_list;
400 if (argc < 2) {
401 printf("Usage: smatch <filename.c>\n");
402 exit(1);
404 sparse_initialize(argc, argv, &filelist);
405 FOR_EACH_PTR_NOTAG(filelist, filename) {
406 sym_list = __sparse(filename);
407 split_functions(sym_list);
408 } END_FOR_EACH_PTR_NOTAG(filename);