The main change here was to completely rewrite how conditions are handled.
[smatch.git] / smatch_flow.c
blob74f7ce583dbcafc7f13d6b53481976ee979da638
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 // printf("%d Debug expr_type %d\n", get_lineno(), expr->type);
36 __smatch_lineno = expr->pos.line;
37 __pass_to_client(expr, EXPR_HOOK);
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_whole_condition(expr->conditional);
77 __use_true_states();
78 __split_expr(expr->cond_true);
79 __use_false_states();
80 __split_expr(expr->cond_false);
81 __merge_true_states();
82 return;
83 case EXPR_CALL:
84 __pass_to_client(expr, FUNCTION_CALL_HOOK);
85 __split_expr(expr->fn);
86 split_expr_list(expr->args);
87 __pass_to_client(expr, FUNCTION_CALL_AFTER_HOOK);
88 #ifdef KERNEL
89 if (expr->fn->type == EXPR_SYMBOL &&
90 !strcmp(expr->fn->symbol_name->name, "panic"))
91 nullify_path();
92 #endif
93 return;
94 case EXPR_INITIALIZER:
95 split_expr_list(expr->expr_list);
96 return;
97 case EXPR_IDENTIFIER:
98 __split_expr(expr->ident_expression);
99 return;
100 case EXPR_INDEX:
101 __split_expr(expr->idx_expression);
102 return;
103 case EXPR_POS:
104 __split_expr(expr->init_expr);
105 return;
106 default:
107 return;
111 static int is_forever_loop(struct statement *stmt)
114 struct expression *expr;
116 expr = stmt->iterator_pre_condition;
117 if (!expr)
118 expr = stmt->iterator_post_condition;
119 if (!expr) {
120 // this is a for(;;) loop...
121 return 1;
124 if (expr->type == EXPR_VALUE && expr->value == 1) {
125 return 1;
128 return 0;
132 * Pre Loops are while and for loops.
135 static void handle_pre_loop(struct statement *stmt)
137 split_statements(stmt->iterator_pre_statement);
139 __push_continues();
140 __push_breaks();
141 __prep_false_only_stack();
143 __split_whole_condition(stmt->iterator_pre_condition);
144 __use_true_states();
146 split_statements(stmt->iterator_statement);
147 split_statements(stmt->iterator_post_statement);
148 if (is_forever_loop(stmt)) {
149 __use_false_only_stack();
150 __pop_continues();
151 __pop_false_states();
152 nullify_path();
153 } else {
154 __merge_continues();
155 __merge_false_states();
156 __use_false_only_stack();
158 __merge_breaks();
162 * Post loops are do {} while();
164 static void handle_post_loop(struct statement *stmt)
166 __push_continues();
167 __push_breaks();
168 split_statements(stmt->iterator_statement);
170 __split_whole_condition(stmt->iterator_post_condition);
171 /* It would prossibly be cleaner to make this all one function */
172 __use_true_states();
173 __use_false_states();
174 __pop_true_states();
176 if (is_forever_loop(stmt)) {
177 __pop_continues();
178 nullify_path();
179 } else {
180 __merge_continues();
182 __merge_breaks();
185 static void split_statements(struct statement *stmt)
187 if (!stmt)
188 return;
190 __smatch_lineno = stmt->pos.line;
191 __pass_to_client(stmt, STMT_HOOK);
193 switch (stmt->type) {
194 case STMT_DECLARATION:
195 __pass_declarations_to_client(stmt->declaration);
196 split_symlist(stmt->declaration);
197 return;
198 case STMT_RETURN:
199 __pass_to_client(stmt, RETURN_HOOK);
200 __split_expr(stmt->ret_value);
201 nullify_path();
202 return;
203 case STMT_EXPRESSION:
204 __split_expr(stmt->expression);
205 return;
206 case STMT_COMPOUND: {
207 struct statement *s;
208 FOR_EACH_PTR(stmt->stmts, s) {
209 split_statements(s);
210 } END_FOR_EACH_PTR(s);
211 return;
213 case STMT_IF:
214 __split_whole_condition(stmt->if_conditional);
215 __use_true_states();
216 split_statements(stmt->if_true);
217 __use_false_states();
218 split_statements(stmt->if_false);
219 __merge_true_states();
220 return;
221 case STMT_ITERATOR:
222 if (stmt->iterator_pre_condition)
223 handle_pre_loop(stmt);
224 else if (stmt->iterator_post_condition)
225 handle_post_loop(stmt);
226 else {
227 // these are for(;;) type loops.
228 handle_pre_loop(stmt);
230 return;
231 case STMT_SWITCH:
232 __split_expr(stmt->switch_expression);
233 __save_switch_states();
234 __push_default();
235 __push_breaks();
236 nullify_path();
237 split_statements(stmt->switch_statement);
238 if (!__pop_default())
239 __merge_switches();
240 __pop_switches();
241 __merge_breaks();
242 return;
243 case STMT_CASE:
244 __merge_switches();
245 if (!stmt->case_expression)
246 __set_default();
247 __split_expr(stmt->case_expression);
248 __split_expr(stmt->case_to);
249 split_statements(stmt->case_statement);
250 return;
251 case STMT_LABEL:
252 if (stmt->label &&
253 stmt->label->type == SYM_LABEL &&
254 stmt->label->ident) {
255 __merge_gotos(stmt->label->ident->name);
257 split_statements(stmt->label_statement);
258 return;
259 case STMT_GOTO:
260 __split_expr(stmt->goto_expression);
261 if (stmt->goto_label && stmt->goto_label->type == SYM_NODE) {
262 if (!strcmp(stmt->goto_label->ident->name, "break")) {
263 __process_breaks();
264 } else if (!strcmp(stmt->goto_label->ident->name,
265 "continue")) {
266 __process_continues();
268 } else if (stmt->goto_label &&
269 stmt->goto_label->type == SYM_LABEL &&
270 stmt->goto_label->ident) {
271 __save_gotos(stmt->goto_label->ident->name);
273 nullify_path();
274 return;
275 case STMT_NONE:
276 return;
277 case STMT_ASM:
278 __split_expr(stmt->asm_string);
279 //__split_expr(stmt->asm_outputs);
280 //__split_expr(stmt->asm_inputs);
281 //__split_expr(stmt->asm_clobbers);
282 return;
283 case STMT_CONTEXT:
284 return;
285 case STMT_RANGE:
286 __split_expr(stmt->range_expression);
287 __split_expr(stmt->range_low);
288 __split_expr(stmt->range_high);
289 return;
293 static void split_expr_list(struct expression_list *expr_list)
295 struct expression *expr;
296 FOR_EACH_PTR(expr_list, expr) {
297 __split_expr(expr);
298 } END_FOR_EACH_PTR(expr);
302 static void split_sym(struct symbol *sym)
304 if (!sym)
305 return;
306 if (!(sym->namespace & NS_SYMBOL))
307 return;
309 __pass_to_client(sym, SYM_HOOK);
310 split_statements(sym->stmt);
311 __split_expr(sym->array_size);
312 split_symlist(sym->arguments);
313 split_symlist(sym->symbol_list);
314 split_statements(sym->inline_stmt);
315 split_symlist(sym->inline_symbol_list);
316 __split_expr(sym->initializer);
319 static void split_symlist(struct symbol_list *sym_list)
321 struct symbol *sym;
323 FOR_EACH_PTR(sym_list, sym) {
324 split_sym(sym);
325 } END_FOR_EACH_PTR(sym);
328 static void split_functions(struct symbol_list *sym_list)
330 struct symbol *sym;
332 FOR_EACH_PTR(sym_list, sym) {
333 struct symbol *base_type;
334 base_type = get_base_type(sym);
335 if (sym->type == SYM_NODE && base_type->type == SYM_FN) {
336 if (base_type->stmt)
337 line_func_start = base_type->stmt->pos.line;
338 if (sym->ident)
339 cur_func = sym->ident->name;
340 __smatch_lineno = sym->pos.line;
341 __pass_to_client(sym, FUNC_DEF_HOOK);
342 split_statements(base_type->stmt);
343 __pass_to_client(sym, END_FUNC_HOOK);
344 cur_func = NULL;
345 line_func_start = 0;
346 clear_all_states();
348 } else {
349 __pass_to_client(sym, BASE_HOOK);
351 } END_FOR_EACH_PTR(sym);
354 void smatch (int argc, char **argv)
357 struct string_list *filelist = NULL;
358 struct symbol_list *sym_list;
360 if (argc < 2) {
361 printf("Usage: smatch <filename.c>\n");
362 exit(1);
364 sparse_initialize(argc, argv, &filelist);
365 FOR_EACH_PTR_NOTAG(filelist, filename) {
366 sym_list = __sparse(filename);
367 split_functions(sym_list);
368 } END_FOR_EACH_PTR_NOTAG(filename);