Handle while and for loops slightly better.
[smatch.git] / smatch_states.c
blobd99cc53a262cbc9968c8ad31f9c9d12cc394695f
1 /*
2 * sparse/smatch_states.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include "smatch.h"
14 ALLOCATOR(smatch_state, "smatch state");
15 DECLARE_PTR_LIST(state_list, struct smatch_state);
16 DECLARE_PTR_LIST(state_list_stack, struct state_list);
18 static struct state_list *cur_slist;
19 static struct state_list_stack *false_stack;
20 static struct state_list_stack *true_stack;
21 static struct state_list_stack *break_stack;
22 static struct state_list_stack *switch_stack;
23 static struct state_list_stack *default_stack;
24 static struct state_list_stack *continue_stack;
25 static struct state_list_stack *mini_false_stack;
26 static struct state_list_stack *false_only_stack;
27 static int false_only_prepped = 0;
28 static struct state_list *and_clumps[2];
30 struct slist_head {
31 char *name;
32 struct state_list *slist;
34 ALLOCATOR(slist_head, "goto stack");
35 DECLARE_PTR_LIST(slist_stack, struct slist_head);
36 static struct slist_stack *goto_stack;
38 int debug_states;
40 void __print_cur_slist()
42 struct smatch_state *state;
44 printf("dumping slist at %d\n", get_lineno());
45 FOR_EACH_PTR(cur_slist, state) {
46 printf("%s=%d\n", state->name, state->state);
47 } END_FOR_EACH_PTR(state);
48 printf("---\n");
51 static void add_history(struct smatch_state *state)
53 struct state_history *tmp;
55 if (!state)
56 return;
57 tmp = malloc(sizeof(*tmp));
58 tmp->loc = get_lineno();
59 add_ptr_list(&state->line_history, tmp);
62 struct smatch_state *alloc_state(const char *name, int owner,
63 struct symbol *sym, int state)
65 struct smatch_state *sm_state = __alloc_smatch_state(0);
67 sm_state->name = (char *)name;
68 sm_state->owner = owner;
69 sm_state->sym = sym;
70 sm_state->state = state;
71 sm_state->line_history = NULL;
72 sm_state->path_history = NULL;
73 add_history(sm_state);
74 return sm_state;
77 static struct smatch_state *clone_state(struct smatch_state *s)
79 return alloc_state(s->name, s->owner, s->sym, s->state);
82 static void push_slist(struct state_list_stack **list_stack,
83 struct state_list *slist)
85 add_ptr_list(list_stack, slist);
88 static struct state_list *pop_slist(struct state_list_stack **list_stack)
90 struct state_list *slist;
92 slist = last_ptr_list((struct ptr_list *)*list_stack);
93 delete_ptr_list_entry((struct ptr_list **)list_stack, slist, 1);
94 return slist;
97 static struct state_list *clone_slist(struct state_list *from_slist)
99 struct smatch_state *state;
100 struct smatch_state *tmp;
101 struct state_list *to_slist = NULL;
103 FOR_EACH_PTR(from_slist, state) {
104 tmp = clone_state(state);
105 add_ptr_list(&to_slist, tmp);
106 } END_FOR_EACH_PTR(state);
107 return to_slist;
110 static void del_slist(struct state_list **slist)
112 __free_ptr_list((struct ptr_list **)slist);
115 static void del_slist_stack(struct state_list_stack **slist_stack)
117 struct state_list *slist;
119 FOR_EACH_PTR(*slist_stack, slist) {
120 __free_ptr_list((struct ptr_list **)&slist);
121 } END_FOR_EACH_PTR(slist);
122 __free_ptr_list((struct ptr_list **)slist_stack);
125 static void add_state_slist(struct state_list **slist,
126 struct smatch_state *state)
128 add_ptr_list(slist, state);
131 static void set_state_slist(struct state_list **slist, const char *name,
132 int owner, struct symbol *sym, int state)
134 struct smatch_state *tmp;
136 FOR_EACH_PTR(*slist, tmp) {
137 if (tmp->owner == owner && tmp->sym == sym
138 && !strcmp(tmp->name, name)){
139 tmp->state = state;
140 return;
142 } END_FOR_EACH_PTR(tmp);
143 tmp = alloc_state(name, owner, sym, state);
144 add_state_slist(slist, tmp);
148 * set_state_stack() sets the state for the top slist on the stack.
150 static inline void set_state_stack(struct state_list_stack **stack,
151 const char *name, int owner,
152 struct symbol *sym, int state)
154 struct state_list *slist;
156 slist = pop_slist(stack);
157 set_state_slist(&slist, name, owner, sym, state);
158 push_slist(stack, slist);
161 static int merge_states(const char *name, int owner, struct symbol *sym,
162 int state1, int state2)
164 int ret;
167 if (state1 == state2)
168 ret = state1;
169 else if (__has_merge_function(owner))
170 ret = __client_merge_function(owner, name, sym, (state1 < state2?state1:state2), (state1 > state2?state1:state2));
171 else
172 ret = UNDEFINED;
174 SM_DEBUG("%d merge name='%s' owner=%d: %d + %d => %d\n",
175 get_lineno(), name, owner, state1, state2, ret);
177 return ret;
180 static void merge_state_slist(struct state_list **slist, const char *name,
181 int owner, struct symbol *sym, int state)
183 struct smatch_state *tmp;
184 int s;
186 FOR_EACH_PTR(*slist, tmp) {
187 if (tmp->owner == owner && tmp->sym == sym
188 && !strcmp(tmp->name, name)){
189 s = merge_states(name, owner, sym, tmp->state, state);
190 if (tmp->state != s) {
191 add_history(tmp);
193 tmp->state = s;
194 return;
196 } END_FOR_EACH_PTR(tmp);
197 tmp = alloc_state(name, owner, sym, state);
198 add_state_slist(slist, tmp);
201 static void merge_state_stack(struct state_list_stack ** stack,
202 const char *name, int owner, struct symbol *sym,
203 int state)
205 struct state_list *slist;
207 slist = pop_slist(stack);
208 merge_state_slist(&slist, name, owner, sym, state);
209 push_slist(stack, slist);
212 static void delete_state_slist(struct state_list **slist, const char *name,
213 int owner, struct symbol *sym)
215 struct smatch_state *state;
217 FOR_EACH_PTR(*slist, state) {
218 if (state->owner == owner && state->sym == sym
219 && !strcmp(state->name, name)){
220 delete_ptr_list_entry((struct ptr_list **)slist,
221 state, 1);
222 __free_smatch_state(state);
223 return;
225 } END_FOR_EACH_PTR(state);
228 static void merge_slist(struct state_list *slist)
230 struct smatch_state *state;
231 FOR_EACH_PTR(slist, state) {
232 merge_state_slist(&cur_slist, state->name, state->owner,
233 state->sym, state->state);
234 } END_FOR_EACH_PTR(state);
237 void set_state(const char *name, int owner, struct symbol *sym, int state)
239 struct smatch_state *tmp;
241 if (!name)
242 return;
244 FOR_EACH_PTR(cur_slist, tmp) {
245 if (tmp->owner == owner && tmp->sym == sym
246 && !strcmp(tmp->name, name)){
247 SM_DEBUG("%d state change name='%s' owner=%d: %d => %d\n"
248 , get_lineno(), name, owner, tmp->state, state);
249 add_history(tmp);
250 tmp->state = state;
251 return;
253 } END_FOR_EACH_PTR(tmp);
254 SM_DEBUG("%d new state. name='%s' owner=%d: %d\n", get_lineno(), name,
255 owner, state);
256 tmp = alloc_state(name, owner, sym, state);
257 add_state_slist(&cur_slist, tmp);
261 static int get_state_slist(struct state_list *slist, const char *name,
262 int owner, struct symbol *sym)
264 struct smatch_state *state;
266 if (!name)
267 return NOTFOUND;
269 FOR_EACH_PTR(cur_slist, state) {
270 if (state->owner == owner && state->sym == sym
271 && !strcmp(state->name, name))
272 return state->state;
273 } END_FOR_EACH_PTR(state);
274 return NOTFOUND;
277 int get_state(const char *name, int owner, struct symbol *sym)
279 return get_state_slist(cur_slist, name, owner, sym);
282 struct state_list *get_current_states(int owner)
284 struct state_list *slist;
285 struct smatch_state *tmp;
287 FOR_EACH_PTR(cur_slist, tmp) {
288 if (tmp->owner == owner) {
289 add_ptr_list(&slist, tmp);
291 } END_FOR_EACH_PTR(tmp);
293 return slist;
296 void set_true_false_states(const char *name, int owner, struct symbol *sym,
297 int true_state, int false_state)
299 int merged = merge_states(name, owner, sym, true_state, false_state);
301 /* fixme. history plus don't call get_state() when not needed*/
302 //SM_DEBUG("%d set_true_false %s. Was %d. Now T:%d F:%d\n",
303 // get_lineno(), name, get_state(name, owner, sym), true_state,
304 // false_state);
306 if (!false_stack || !true_stack || !mini_false_stack) {
307 printf("Error: missing true/false stacks\n");
308 return;
310 if (__negate()) {
311 int tmp = true_state;
313 true_state = false_state;
314 false_state = tmp;
316 set_state(name, owner, sym, true_state);
317 set_state_stack(&mini_false_stack, name, owner, sym, false_state);
318 set_state_slist(&and_clumps[1], name, owner, sym, true_state);
319 set_state_stack(&true_stack, name, owner, sym,
320 (__ors?merged:true_state));
321 set_state_stack(&false_stack, name, owner, sym,
322 (__ands?merged:false_state));
323 if (false_only_prepped)
324 set_state_stack(&false_only_stack, name, owner, sym, false_state);
327 void delete_state(const char *name, int owner, struct symbol *sym)
329 delete_state_slist(&cur_slist, name, owner, sym);
332 void nullify_path()
334 del_slist(&cur_slist);
337 void clear_all_states()
339 struct slist_head *slist_head;
341 nullify_path();
342 del_slist_stack(&false_stack);
343 del_slist_stack(&true_stack);
344 del_slist_stack(&break_stack);
345 del_slist_stack(&switch_stack);
346 del_slist_stack(&continue_stack);
347 del_slist_stack(&mini_false_stack);
348 del_slist(&and_clumps[0]);
349 del_slist(&and_clumps[1]);
351 FOR_EACH_PTR(goto_stack, slist_head) {
352 del_slist(&slist_head->slist);
353 } END_FOR_EACH_PTR(slist_head);
354 __free_ptr_list((struct ptr_list **)&goto_stack);
357 void __first_and_clump()
359 del_slist(&and_clumps[0]);
360 and_clumps[0] = and_clumps[1];
361 and_clumps[1] = NULL;
364 void __merge_and_clump()
366 struct smatch_state *tmp;
368 FOR_EACH_PTR(and_clumps[0], tmp) {
369 if (tmp->state != get_state_slist(and_clumps[1], tmp->name,
370 tmp->owner, tmp->sym))
371 DELETE_CURRENT_PTR(tmp);
372 } END_FOR_EACH_PTR(tmp);
373 del_slist(&and_clumps[1]);
376 void __use_and_clumps()
378 struct smatch_state *tmp;
380 FOR_EACH_PTR(and_clumps[0], tmp) {
381 if (tmp)
382 set_state_stack(&true_stack, tmp->name, tmp->owner,
383 tmp->sym, tmp->state);
384 } END_FOR_EACH_PTR(tmp);
385 del_slist(&and_clumps[0]);
388 void __split_false_states_mini()
390 push_slist(&mini_false_stack, clone_slist(cur_slist));
393 void __use_false_states_mini()
395 struct state_list *slist;
397 nullify_path();
398 slist = pop_slist(&mini_false_stack);
399 merge_slist(slist);
400 del_slist(&slist);
403 void __pop_false_states_mini()
405 struct state_list *slist;
407 slist = pop_slist(&mini_false_stack);
408 del_slist(&slist);
411 void __prep_false_only_stack()
413 push_slist(&false_only_stack, NULL);
414 false_only_prepped = 1;
417 void __use_false_only_stack()
419 struct state_list *slist;
420 struct smatch_state *tmp;
422 slist = pop_slist(&false_only_stack);
423 FOR_EACH_PTR(slist, tmp) {
424 set_state(tmp->name, tmp->owner, tmp->sym, tmp->state);
425 } END_FOR_EACH_PTR(tmp);
426 del_slist(&slist);
427 false_only_prepped = 0;
430 void __split_true_false_paths()
432 push_slist(&false_stack, clone_slist(cur_slist));
433 push_slist(&true_stack, clone_slist(cur_slist));
434 __split_false_states_mini();
437 void __use_true_states()
439 struct state_list *slist;
441 __pop_false_states_mini();
442 nullify_path();
443 slist = pop_slist(&true_stack);
444 merge_slist(slist);
445 del_slist(&slist);
448 void __use_false_states()
450 struct state_list *slist;
452 push_slist(&true_stack, clone_slist(cur_slist));
453 nullify_path();
454 slist = pop_slist(&false_stack);
455 merge_slist(slist);
456 del_slist(&slist);
459 void __pop_false_states()
461 struct state_list *slist;
463 slist = pop_slist(&false_stack);
464 del_slist(&slist);
467 void __merge_false_states()
469 struct state_list *slist;
471 slist = pop_slist(&false_stack);
472 merge_slist(slist);
473 del_slist(&slist);
476 void __merge_true_states()
478 struct state_list *slist;
480 slist = pop_slist(&true_stack);
481 merge_slist(slist);
482 del_slist(&slist);
485 void __pop_true_states()
487 struct state_list *slist;
489 slist = pop_slist(&true_stack);
490 del_slist(&slist);
493 void __push_continues()
495 push_slist(&continue_stack, NULL);
498 void __pop_continues()
500 struct state_list *slist;
502 slist = pop_slist(&continue_stack);
503 del_slist(&slist);
506 void __process_continues()
508 struct smatch_state *state;
510 FOR_EACH_PTR(cur_slist, state) {
511 merge_state_stack(&continue_stack, state->name, state->owner,
512 state->sym, state->state);
513 } END_FOR_EACH_PTR(state);
516 void __merge_continues()
518 struct state_list *slist;
520 slist = pop_slist(&continue_stack);
521 merge_slist(slist);
522 del_slist(&slist);
525 void __push_breaks()
527 push_slist(&break_stack, NULL);
530 void __process_breaks()
532 struct smatch_state *state;
534 FOR_EACH_PTR(cur_slist, state) {
535 merge_state_stack(&break_stack, state->name, state->owner,
536 state->sym, state->state);
537 } END_FOR_EACH_PTR(state);
540 void __merge_breaks()
542 struct state_list *slist;
544 slist = pop_slist(&break_stack);
545 merge_slist(slist);
546 del_slist(&slist);
549 void __pop_breaks()
551 struct state_list *slist;
553 slist = pop_slist(&break_stack);
554 del_slist(&slist);
557 void __save_switch_states()
559 push_slist(&switch_stack, clone_slist(cur_slist));
562 void __merge_switches()
564 struct state_list *slist;
566 slist = pop_slist(&switch_stack);
567 merge_slist(slist);
568 push_slist(&switch_stack, slist);
571 void __pop_switches()
573 struct state_list *slist;
575 slist = pop_slist(&switch_stack);
576 del_slist(&slist);
579 void __push_default()
581 push_slist(&default_stack, NULL);
582 set_state_stack(&default_stack, "has_default", 0, NULL, 0);
585 void __set_default()
587 set_state_stack(&default_stack, "has_default", 0, NULL, 1);
590 int __pop_default()
592 struct state_list *slist;
593 struct smatch_state *state;
595 int ret = -1;
596 slist = pop_slist(&default_stack);
597 FOR_EACH_PTR(slist, state) {
598 if (!strcmp(state->name, "has_default"))
599 ret = state->state;
600 } END_FOR_EACH_PTR(state);
601 del_slist(&slist);
602 return ret;
605 static struct slist_head *alloc_slist_head(const char *name,
606 struct state_list *slist)
608 struct slist_head *slist_head = __alloc_slist_head(0);
610 slist_head->name = (char *)name;
611 slist_head->slist = slist;
612 return slist_head;
615 static struct state_list *get_slist_from_slist_stack(const char *name)
617 struct slist_head *tmp;
619 FOR_EACH_PTR(goto_stack, tmp) {
620 if (!strcmp(tmp->name, name))
621 return tmp->slist;
622 } END_FOR_EACH_PTR(tmp);
623 return NULL;
626 void __save_gotos(const char *name)
628 struct state_list *slist;
630 slist = get_slist_from_slist_stack(name);
631 if (slist) {
632 struct smatch_state *state;
633 FOR_EACH_PTR(cur_slist, state) {
634 merge_state_slist(&slist, state->name, state->owner,
635 state->sym, state->state);
636 } END_FOR_EACH_PTR(state);
637 return;
638 } else {
639 struct state_list *slist;
640 struct slist_head *slist_head;
641 slist = clone_slist(cur_slist);
642 slist_head = alloc_slist_head(name, slist);
643 add_ptr_list(&goto_stack, slist_head);
647 void __merge_gotos(const char *name)
649 struct state_list *slist;
651 slist = get_slist_from_slist_stack(name);
652 merge_slist(slist);