implied: update to stree
[smatch.git] / smatch_slist.c
blobe52fa9b0969ce4ed41685d98496734a8ee7429c0
1 /*
2 * Copyright (C) 2008,2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include "smatch.h"
21 #include "smatch_slist.h"
23 #undef CHECKORDER
25 ALLOCATOR(smatch_state, "smatch state");
26 ALLOCATOR(sm_state, "sm state");
27 ALLOCATOR(named_slist, "named slist");
28 ALLOCATOR(named_stree, "named slist");
29 __DO_ALLOCATOR(char, 1, 4, "state names", sname);
31 static int sm_state_counter;
33 char *show_sm(struct sm_state *sm)
35 static char buf[256];
36 struct sm_state *tmp;
37 int pos;
38 int i;
40 pos = snprintf(buf, sizeof(buf), "[%s] '%s' = %s (",
41 check_name(sm->owner), sm->name, show_state(sm->state));
42 if (pos > sizeof(buf))
43 goto truncate;
45 i = 0;
46 FOR_EACH_PTR(sm->possible, tmp) {
47 if (i++)
48 pos += snprintf(buf + pos, sizeof(buf) - pos, ", ");
49 if (pos > sizeof(buf))
50 goto truncate;
51 pos += snprintf(buf + pos, sizeof(buf) - pos, "%s",
52 show_state(tmp->state));
53 if (pos > sizeof(buf))
54 goto truncate;
55 } END_FOR_EACH_PTR(tmp);
56 snprintf(buf + pos, sizeof(buf) - pos, ")");
58 return buf;
60 truncate:
61 for (i = 0; i < 3; i++)
62 buf[sizeof(buf) - 2 - i] = '.';
63 return buf;
66 void __print_slist(struct state_list *slist)
68 struct sm_state *sm;
70 printf("dumping slist at %d\n", get_lineno());
71 FOR_EACH_PTR(slist, sm) {
72 printf("%s\n", show_sm(sm));
73 } END_FOR_EACH_PTR(sm);
74 printf("---\n");
77 void __print_stree(struct AVL *stree)
79 struct sm_state *sm;
81 printf("dumping stree at %d\n", get_lineno());
82 FOR_EACH_SM(stree, sm) {
83 printf("%s\n", show_sm(sm));
84 } END_FOR_EACH_SM(sm);
85 printf("---\n");
88 /* NULL states go at the end to simplify merge_slist */
89 int cmp_tracker(const struct sm_state *a, const struct sm_state *b)
91 int ret;
93 if (a == b)
94 return 0;
95 if (!b)
96 return -1;
97 if (!a)
98 return 1;
100 if (a->owner > b->owner)
101 return -1;
102 if (a->owner < b->owner)
103 return 1;
105 ret = strcmp(a->name, b->name);
106 if (ret)
107 return ret;
109 if (!b->sym && a->sym)
110 return -1;
111 if (!a->sym && b->sym)
112 return 1;
113 if (a->sym > b->sym)
114 return -1;
115 if (a->sym < b->sym)
116 return 1;
118 return 0;
121 static int cmp_sm_states(const struct sm_state *a, const struct sm_state *b, int preserve)
123 int ret;
125 ret = cmp_tracker(a, b);
126 if (ret)
127 return ret;
129 /* todo: add hook for smatch_extra.c */
130 if (a->state > b->state)
131 return -1;
132 if (a->state < b->state)
133 return 1;
134 /* This is obviously a massive disgusting hack but we need to preserve
135 * the unmerged states for smatch extra because we use them in
136 * smatch_db.c. Meanwhile if we preserve all the other unmerged states
137 * then it uses a lot of memory and we don't use it. Hence this hack.
139 * Also sometimes even just preserving every possible SMATCH_EXTRA state
140 * takes too much resources so we have to cap that. Capping is probably
141 * not often a problem in real life.
143 if (a->owner == SMATCH_EXTRA && preserve) {
144 if (a == b)
145 return 0;
146 if (a->merged == 1 && b->merged == 0)
147 return -1;
148 if (a->merged == 0)
149 return 1;
152 return 0;
155 static struct sm_state *alloc_sm_state(int owner, const char *name,
156 struct symbol *sym, struct smatch_state *state)
158 struct sm_state *sm_state = __alloc_sm_state(0);
160 sm_state_counter++;
162 sm_state->name = alloc_sname(name);
163 sm_state->owner = owner;
164 sm_state->sym = sym;
165 sm_state->state = state;
166 sm_state->line = get_lineno();
167 sm_state->merged = 0;
168 sm_state->implied = 0;
169 sm_state->pool = NULL;
170 sm_state->left = NULL;
171 sm_state->right = NULL;
172 sm_state->nr_children = 1;
173 sm_state->possible = NULL;
174 add_ptr_list(&sm_state->possible, sm_state);
175 return sm_state;
178 static struct sm_state *alloc_state_no_name(int owner, const char *name,
179 struct symbol *sym,
180 struct smatch_state *state)
182 struct sm_state *tmp;
184 tmp = alloc_sm_state(owner, NULL, sym, state);
185 tmp->name = name;
186 return tmp;
189 int too_many_possible(struct sm_state *sm)
191 if (ptr_list_size((struct ptr_list *)sm->possible) >= 100)
192 return 1;
193 return 0;
196 void add_possible_sm(struct sm_state *to, struct sm_state *new)
198 struct sm_state *tmp;
199 int preserve = 1;
201 if (too_many_possible(to))
202 preserve = 0;
204 FOR_EACH_PTR(to->possible, tmp) {
205 if (cmp_sm_states(tmp, new, preserve) < 0)
206 continue;
207 else if (cmp_sm_states(tmp, new, preserve) == 0) {
208 return;
209 } else {
210 INSERT_CURRENT(new, tmp);
211 return;
213 } END_FOR_EACH_PTR(tmp);
214 add_ptr_list(&to->possible, new);
217 static void copy_possibles(struct sm_state *to, struct sm_state *from)
219 struct sm_state *tmp;
221 FOR_EACH_PTR(from->possible, tmp) {
222 add_possible_sm(to, tmp);
223 } END_FOR_EACH_PTR(tmp);
226 char *alloc_sname(const char *str)
228 char *tmp;
230 if (!str)
231 return NULL;
232 tmp = __alloc_sname(strlen(str) + 1);
233 strcpy(tmp, str);
234 return tmp;
237 int out_of_memory()
240 * I decided to use 50M here based on trial and error.
241 * It works out OK for the kernel and so it should work
242 * for most other projects as well.
244 if (sm_state_counter * sizeof(struct sm_state) >= 50000000)
245 return 1;
246 return 0;
249 int low_on_memory(void)
251 if (sm_state_counter * sizeof(struct sm_state) >= 25000000)
252 return 1;
253 return 0;
256 static void free_sm_state(struct sm_state *sm)
258 free_slist(&sm->possible);
260 * fixme. Free the actual state.
261 * Right now we leave it until the end of the function
262 * because we don't want to double free it.
263 * Use the freelist to not double free things
267 static void free_all_sm_states(struct allocation_blob *blob)
269 unsigned int size = sizeof(struct sm_state);
270 unsigned int offset = 0;
272 while (offset < blob->offset) {
273 free_sm_state((struct sm_state *)(blob->data + offset));
274 offset += size;
278 /* At the end of every function we free all the sm_states */
279 void free_every_single_sm_state(void)
281 struct allocator_struct *desc = &sm_state_allocator;
282 struct allocation_blob *blob = desc->blobs;
284 desc->blobs = NULL;
285 desc->allocations = 0;
286 desc->total_bytes = 0;
287 desc->useful_bytes = 0;
288 desc->freelist = NULL;
289 while (blob) {
290 struct allocation_blob *next = blob->next;
291 free_all_sm_states(blob);
292 blob_free(blob, desc->chunking);
293 blob = next;
295 clear_sname_alloc();
296 clear_smatch_state_alloc();
298 sm_state_counter = 0;
301 struct sm_state *clone_sm(struct sm_state *s)
303 struct sm_state *ret;
305 ret = alloc_state_no_name(s->owner, s->name, s->sym, s->state);
306 ret->merged = s->merged;
307 ret->implied = s->implied;
308 ret->line = s->line;
309 /* clone_sm() doesn't copy the pools. Each state needs to have
310 only one pool. */
311 ret->possible = clone_slist(s->possible);
312 ret->left = s->left;
313 ret->right = s->right;
314 ret->nr_children = s->nr_children;
315 return ret;
318 int is_merged(struct sm_state *sm)
320 return sm->merged;
323 int is_implied(struct sm_state *sm)
325 return sm->implied;
328 int slist_has_state(struct state_list *slist, struct smatch_state *state)
330 struct sm_state *tmp;
332 FOR_EACH_PTR(slist, tmp) {
333 if (tmp->state == state)
334 return 1;
335 } END_FOR_EACH_PTR(tmp);
336 return 0;
339 static void check_order(struct state_list *slist)
341 #ifdef CHECKORDER
342 struct sm_state *sm;
343 struct sm_state *last = NULL;
344 int printed = 0;
346 FOR_EACH_PTR(slist, sm) {
347 if (last && cmp_tracker(sm, last) <= 0) {
348 printf("Error. Unsorted slist %d vs %d, %p vs %p, "
349 "%s vs %s\n", last->owner, sm->owner,
350 last->sym, sm->sym, last->name, sm->name);
351 printed = 1;
353 last = sm;
354 } END_FOR_EACH_PTR(sm);
356 if (printed)
357 printf("======\n");
358 #endif
361 struct state_list *clone_slist(struct state_list *from_slist)
363 struct sm_state *sm;
364 struct state_list *to_slist = NULL;
366 FOR_EACH_PTR(from_slist, sm) {
367 add_ptr_list(&to_slist, sm);
368 } END_FOR_EACH_PTR(sm);
369 return to_slist;
372 struct state_list_stack *clone_stack(struct state_list_stack *from_stack)
374 struct state_list *slist;
375 struct state_list_stack *to_stack = NULL;
377 FOR_EACH_PTR(from_stack, slist) {
378 push_slist(&to_stack, slist);
379 } END_FOR_EACH_PTR(slist);
380 return to_stack;
383 struct smatch_state *merge_states(int owner, const char *name,
384 struct symbol *sym,
385 struct smatch_state *state1,
386 struct smatch_state *state2)
388 struct smatch_state *ret;
390 if (state1 == state2)
391 ret = state1;
392 else if (__has_merge_function(owner))
393 ret = __client_merge_function(owner, state1, state2);
394 else if (!state1 || !state2)
395 ret = &undefined;
396 else
397 ret = &merged;
398 return ret;
401 struct sm_state *merge_sm_states(struct sm_state *one, struct sm_state *two)
403 struct smatch_state *s;
404 struct sm_state *result;
406 if (one == two)
407 return one;
408 s = merge_states(one->owner, one->name, one->sym, one->state, two->state);
409 result = alloc_state_no_name(one->owner, one->name, one->sym, s);
410 result->merged = 1;
411 result->left = one;
412 result->right = two;
413 result->nr_children = one->nr_children + two->nr_children;
414 copy_possibles(result, one);
415 copy_possibles(result, two);
417 if (option_debug ||
418 strcmp(check_name(one->owner), option_debug_check) == 0) {
419 struct sm_state *tmp;
420 int i = 0;
422 printf("%d merge [%s] '%s' %s(L %d) + %s(L %d) => %s (",
423 get_lineno(), check_name(one->owner), one->name,
424 show_state(one->state), one->line,
425 show_state(two->state), two->line,
426 show_state(s));
428 FOR_EACH_PTR(result->possible, tmp) {
429 if (i++)
430 printf(", ");
431 printf("%s", show_state(tmp->state));
432 } END_FOR_EACH_PTR(tmp);
433 printf(")\n");
436 return result;
439 struct sm_state *get_sm_state_slist(struct state_list *slist, int owner, const char *name,
440 struct symbol *sym)
442 struct sm_state *sm;
444 if (!name)
445 return NULL;
447 FOR_EACH_PTR(slist, sm) {
448 if (sm->owner == owner && sm->sym == sym && !strcmp(sm->name, name))
449 return sm;
450 } END_FOR_EACH_PTR(sm);
451 return NULL;
454 struct sm_state *get_sm_state_stree(struct AVL *stree, int owner, const char *name,
455 struct symbol *sym)
457 struct tracker tracker = {
458 .owner = owner,
459 .name = (char *)name,
460 .sym = sym,
463 if (!name)
464 return NULL;
467 return avl_lookup(stree, (struct sm_state *)&tracker);
470 struct smatch_state *get_state_slist(struct state_list *slist,
471 int owner, const char *name,
472 struct symbol *sym)
474 struct sm_state *sm;
476 sm = get_sm_state_slist(slist, owner, name, sym);
477 if (sm)
478 return sm->state;
479 return NULL;
482 struct smatch_state *get_state_stree(struct AVL *stree,
483 int owner, const char *name,
484 struct symbol *sym)
486 struct sm_state *sm;
488 sm = get_sm_state_stree(stree, owner, name, sym);
489 if (sm)
490 return sm->state;
491 return NULL;
494 void overwrite_sm_state(struct state_list **slist, struct sm_state *new)
496 struct sm_state *tmp;
498 FOR_EACH_PTR(*slist, tmp) {
499 if (cmp_tracker(tmp, new) < 0)
500 continue;
501 else if (cmp_tracker(tmp, new) == 0) {
502 REPLACE_CURRENT_PTR(tmp, new);
503 return;
504 } else {
505 INSERT_CURRENT(new, tmp);
506 return;
508 } END_FOR_EACH_PTR(tmp);
509 add_ptr_list(slist, new);
512 /* FIXME: this is almost exactly the same as set_sm_state_slist() */
513 void overwrite_sm_state_stree(struct AVL **stree, struct sm_state *new)
515 avl_insert(stree, new);
518 void overwrite_sm_state_stack(struct state_list_stack **stack,
519 struct sm_state *sm)
521 struct state_list *slist;
523 slist = pop_slist(stack);
524 overwrite_sm_state(&slist, sm);
525 push_slist(stack, slist);
528 void overwrite_sm_state_stree_stack(struct stree_stack **stack,
529 struct sm_state *sm)
531 struct AVL *stree;
533 stree = pop_stree(stack);
534 overwrite_sm_state_stree(&stree, sm);
535 push_stree(stack, stree);
538 struct sm_state *set_state_slist(struct state_list **slist, int owner, const char *name,
539 struct symbol *sym, struct smatch_state *state)
541 struct sm_state *tmp;
542 struct sm_state *new = alloc_sm_state(owner, name, sym, state);
544 FOR_EACH_PTR(*slist, tmp) {
545 if (cmp_tracker(tmp, new) < 0)
546 continue;
547 else if (cmp_tracker(tmp, new) == 0) {
548 REPLACE_CURRENT_PTR(tmp, new);
549 return new;
550 } else {
551 INSERT_CURRENT(new, tmp);
552 return new;
554 } END_FOR_EACH_PTR(tmp);
555 add_ptr_list(slist, new);
556 return new;
559 struct sm_state *set_state_stree(struct AVL **stree, int owner, const char *name,
560 struct symbol *sym, struct smatch_state *state)
562 struct sm_state *new = alloc_sm_state(owner, name, sym, state);
564 avl_insert(stree, new);
565 return new;
568 void delete_state_slist(struct state_list **slist, int owner, const char *name,
569 struct symbol *sym)
571 struct sm_state *sm;
573 FOR_EACH_PTR(*slist, sm) {
574 if (sm->owner == owner && sm->sym == sym && !strcmp(sm->name, name)) {
575 DELETE_CURRENT_PTR(sm);
576 return;
578 } END_FOR_EACH_PTR(sm);
581 void delete_state_stree(struct AVL **stree, int owner, const char *name,
582 struct symbol *sym)
584 struct tracker tracker = {
585 .owner = owner,
586 .name = (char *)name,
587 .sym = sym,
590 avl_remove(stree, (struct sm_state *)&tracker);
593 void delete_state_stack(struct state_list_stack **stack, int owner, const char *name,
594 struct symbol *sym)
596 struct state_list *slist;
598 slist = pop_slist(stack);
599 delete_state_slist(&slist, owner, name, sym);
600 push_slist(stack, slist);
603 void delete_state_stree_stack(struct stree_stack **stack, int owner, const char *name,
604 struct symbol *sym)
606 struct AVL *stree;
608 stree = pop_stree(stack);
609 delete_state_stree(&stree, owner, name, sym);
610 push_stree(stack, stree);
613 void push_slist(struct state_list_stack **list_stack, struct state_list *slist)
615 add_ptr_list(list_stack, slist);
618 struct state_list *pop_slist(struct state_list_stack **list_stack)
620 struct state_list *slist;
622 slist = last_ptr_list((struct ptr_list *)*list_stack);
623 delete_ptr_list_last((struct ptr_list **)list_stack);
624 return slist;
627 void push_stree(struct stree_stack **stack, struct AVL *stree)
629 add_ptr_list(stack, stree);
632 struct AVL *pop_stree(struct stree_stack **stack)
634 struct AVL *stree;
636 stree = last_ptr_list((struct ptr_list *)*stack);
637 delete_ptr_list_last((struct ptr_list **)stack);
638 return stree;
641 void free_slist(struct state_list **slist)
643 __free_ptr_list((struct ptr_list **)slist);
646 void free_stack(struct state_list_stack **stack)
648 __free_ptr_list((struct ptr_list **)stack);
651 void free_stack_and_slists(struct state_list_stack **slist_stack)
653 struct state_list *slist;
655 FOR_EACH_PTR(*slist_stack, slist) {
656 free_slist(&slist);
657 } END_FOR_EACH_PTR(slist);
658 free_stack(slist_stack);
661 void free_stree(struct AVL **stree)
663 avl_free(stree);
666 void free_stree_stack(struct stree_stack **stack)
668 __free_ptr_list((struct ptr_list **)stack);
671 void free_stack_and_strees(struct stree_stack **stree_stack)
673 struct AVL *stree;
675 FOR_EACH_PTR(*stree_stack, stree) {
676 free_stree(&stree);
677 } END_FOR_EACH_PTR(stree);
678 free_stree_stack(stree_stack);
682 * set_state_stack() sets the state for the top slist on the stack.
684 struct sm_state *set_state_stack(struct state_list_stack **stack, int owner, const char *name,
685 struct symbol *sym, struct smatch_state *state)
687 struct state_list *slist;
688 struct sm_state *sm;
690 slist = pop_slist(stack);
691 sm = set_state_slist(&slist, owner, name, sym, state);
692 push_slist(stack, slist);
694 return sm;
697 struct sm_state *set_state_stree_stack(struct stree_stack **stack, int owner, const char *name,
698 struct symbol *sym, struct smatch_state *state)
700 struct AVL *stree;
701 struct sm_state *sm;
703 stree = pop_stree(stack);
704 sm = set_state_stree(&stree, owner, name, sym, state);
705 push_stree(stack, stree);
707 return sm;
711 * get_sm_state_stack() gets the state for the top slist on the stack.
713 struct sm_state *get_sm_state_stack(struct state_list_stack *stack,
714 int owner, const char *name,
715 struct symbol *sym)
717 struct state_list *slist;
718 struct sm_state *ret;
720 slist = pop_slist(&stack);
721 ret = get_sm_state_slist(slist, owner, name, sym);
722 push_slist(&stack, slist);
723 return ret;
726 struct sm_state *get_sm_state_stree_stack(struct stree_stack *stack,
727 int owner, const char *name,
728 struct symbol *sym)
730 struct AVL *stree;
731 struct sm_state *ret;
733 stree = pop_stree(&stack);
734 ret = get_sm_state_stree(stree, owner, name, sym);
735 push_stree(&stack, stree);
736 return ret;
739 struct smatch_state *get_state_stack(struct state_list_stack *stack,
740 int owner, const char *name,
741 struct symbol *sym)
743 struct sm_state *sm;
745 sm = get_sm_state_stack(stack, owner, name, sym);
746 if (sm)
747 return sm->state;
748 return NULL;
751 struct smatch_state *get_state_stree_stack(struct stree_stack *stack,
752 int owner, const char *name,
753 struct symbol *sym)
755 struct sm_state *sm;
757 sm = get_sm_state_stree_stack(stack, owner, name, sym);
758 if (sm)
759 return sm->state;
760 return NULL;
763 static void match_states(struct state_list **one, struct state_list **two)
765 struct sm_state *one_sm;
766 struct sm_state *two_sm;
767 struct sm_state *tmp;
768 struct smatch_state *tmp_state;
769 struct state_list *add_to_one = NULL;
770 struct state_list *add_to_two = NULL;
772 PREPARE_PTR_LIST(*one, one_sm);
773 PREPARE_PTR_LIST(*two, two_sm);
774 for (;;) {
775 if (!one_sm && !two_sm)
776 break;
777 if (cmp_tracker(one_sm, two_sm) < 0) {
778 __set_fake_cur_slist_fast(*two);
779 tmp_state = __client_unmatched_state_function(one_sm);
780 __pop_fake_cur_slist_fast();
781 tmp = alloc_state_no_name(one_sm->owner, one_sm->name,
782 one_sm->sym, tmp_state);
783 add_ptr_list(&add_to_two, tmp);
784 NEXT_PTR_LIST(one_sm);
785 } else if (cmp_tracker(one_sm, two_sm) == 0) {
786 NEXT_PTR_LIST(one_sm);
787 NEXT_PTR_LIST(two_sm);
788 } else {
789 __set_fake_cur_slist_fast(*one);
790 tmp_state = __client_unmatched_state_function(two_sm);
791 __pop_fake_cur_slist_fast();
792 tmp = alloc_state_no_name(two_sm->owner, two_sm->name,
793 two_sm->sym, tmp_state);
794 add_ptr_list(&add_to_one, tmp);
795 NEXT_PTR_LIST(two_sm);
798 FINISH_PTR_LIST(two_sm);
799 FINISH_PTR_LIST(one_sm);
801 overwrite_slist(add_to_one, one);
802 overwrite_slist(add_to_two, two);
805 static void match_states_stree(struct AVL **one, struct AVL **two)
807 struct smatch_state *tmp_state;
808 struct sm_state *tmp_sm;
809 struct AVL *add_to_one = NULL;
810 struct AVL *add_to_two = NULL;
811 AvlIter one_iter;
812 AvlIter two_iter;
814 avl_iter_begin(&one_iter, *one, FORWARD);
815 avl_iter_begin(&two_iter, *two, FORWARD);
817 for (;;) {
818 if (!one_iter.sm && !two_iter.sm)
819 break;
820 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
821 __set_fake_cur_stree_fast(*two);
822 tmp_state = __client_unmatched_state_function(one_iter.sm);
823 __pop_fake_cur_stree_fast();
824 tmp_sm = alloc_state_no_name(one_iter.sm->owner, one_iter.sm->name,
825 one_iter.sm->sym, tmp_state);
826 avl_insert(&add_to_two, tmp_sm);
827 avl_iter_next(&one_iter);
828 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
829 avl_iter_next(&one_iter);
830 avl_iter_next(&two_iter);
831 } else {
832 __set_fake_cur_stree_fast(*one);
833 tmp_state = __client_unmatched_state_function(two_iter.sm);
834 __pop_fake_cur_stree_fast();
835 tmp_sm = alloc_state_no_name(two_iter.sm->owner, two_iter.sm->name,
836 two_iter.sm->sym, tmp_state);
837 avl_insert(&add_to_one, tmp_sm);
838 avl_iter_next(&two_iter);
842 overwrite_stree(add_to_one, one);
843 overwrite_stree(add_to_two, two);
846 static void clone_pool_havers(struct state_list *slist)
848 struct sm_state *sm;
849 struct sm_state *new;
851 FOR_EACH_PTR(slist, sm) {
852 if (sm->pool) {
853 new = clone_sm(sm);
854 REPLACE_CURRENT_PTR(sm, new);
856 } END_FOR_EACH_PTR(sm);
859 static void clone_pool_havers_stree(struct AVL *stree)
861 struct AvlIter iter;
863 avl_foreach(iter, stree) {
864 if (iter.sm->pool)
865 iter.sm = clone_sm(iter.sm);
869 int __slist_id;
871 * Sets the first state to the slist_id.
873 static void set_slist_id(struct state_list *slist)
875 struct smatch_state *state;
876 struct sm_state *tmp, *new;
878 state = alloc_state_num(++__slist_id);
879 new = alloc_sm_state(-1, "unnull_path", NULL, state);
881 FOR_EACH_PTR(slist, tmp) {
882 if (tmp->owner != (unsigned short)-1)
883 return;
884 REPLACE_CURRENT_PTR(tmp, new);
885 return;
886 } END_FOR_EACH_PTR(tmp);
889 static void set_stree_id(struct AVL *stree)
891 struct smatch_state *state;
892 struct sm_state *new;
894 /* FIXME: This is horrible. Anyway, slist_id should be a part of the
895 AVL pointer */
897 state = alloc_state_num(++__slist_id);
898 new = alloc_sm_state(-1, "unnull_path", NULL, state);
900 if (!avl_member(stree, new))
901 return;
902 avl_insert(&stree, new);
905 int get_slist_id(struct state_list *slist)
907 struct sm_state *tmp;
909 FOR_EACH_PTR(slist, tmp) {
910 if (tmp->owner != (unsigned short)-1)
911 return 0;
912 return PTR_INT(tmp->state->data);
913 } END_FOR_EACH_PTR(tmp);
914 return 0;
917 int get_stree_id(struct AVL *stree)
919 struct sm_state *sm;
921 sm = get_sm_state_stree(stree, -1, "unnull_path", NULL);
922 if (sm)
923 return PTR_INT(sm->state->data);
924 return 0;
928 * merge_slist() is called whenever paths merge, such as after
929 * an if statement. It takes the two slists and creates one.
931 void merge_slist(struct state_list **to, struct state_list *slist)
933 struct sm_state *one_sm, *two_sm, *tmp;
934 struct state_list *results = NULL;
935 struct state_list *implied_one = NULL;
936 struct state_list *implied_two = NULL;
938 if (out_of_memory())
939 return;
941 check_order(*to);
942 check_order(slist);
944 /* merging a null and nonnull path gives you only the nonnull path */
945 if (!slist)
946 return;
948 if (!*to) {
949 *to = clone_slist(slist);
950 return;
953 implied_one = clone_slist(*to);
954 implied_two = clone_slist(slist);
956 match_states(&implied_one, &implied_two);
958 clone_pool_havers(implied_one);
959 clone_pool_havers(implied_two);
961 set_slist_id(implied_one);
962 set_slist_id(implied_two);
964 PREPARE_PTR_LIST(implied_one, one_sm);
965 PREPARE_PTR_LIST(implied_two, two_sm);
966 for (;;) {
967 if (!one_sm && !two_sm)
968 break;
969 if (cmp_tracker(one_sm, two_sm) < 0) {
970 sm_msg("error: Internal smatch error.");
971 NEXT_PTR_LIST(one_sm);
972 } else if (cmp_tracker(one_sm, two_sm) == 0) {
973 if (one_sm != two_sm) {
974 one_sm->pool = implied_one;
975 two_sm->pool = implied_two;
978 tmp = merge_sm_states(one_sm, two_sm);
979 add_ptr_list(&results, tmp);
980 NEXT_PTR_LIST(one_sm);
981 NEXT_PTR_LIST(two_sm);
982 } else {
983 sm_msg("error: Internal smatch error.");
984 NEXT_PTR_LIST(two_sm);
987 FINISH_PTR_LIST(two_sm);
988 FINISH_PTR_LIST(one_sm);
990 free_slist(to);
991 *to = results;
994 void merge_stree(struct AVL **to, struct AVL *stree)
996 struct AVL *results = NULL;
997 struct AVL *implied_one = NULL;
998 struct AVL *implied_two = NULL;
999 AvlIter one_iter;
1000 AvlIter two_iter;
1001 struct sm_state *tmp_sm;
1002 struct state_list *implied_one_slist;
1003 struct state_list *implied_two_slist;
1005 if (out_of_memory())
1006 return;
1008 /* merging a null and nonnull path gives you only the nonnull path */
1009 if (!stree)
1010 return;
1012 if (!*to) {
1013 *to = avl_clone(stree);
1014 return;
1017 implied_one = avl_clone(*to);
1018 implied_two = avl_clone(stree);
1020 match_states_stree(&implied_one, &implied_two);
1022 clone_pool_havers_stree(implied_one);
1023 clone_pool_havers_stree(implied_two);
1025 set_stree_id(implied_one);
1026 set_stree_id(implied_two);
1028 implied_one_slist = stree_to_slist(implied_one);
1029 implied_two_slist = stree_to_slist(implied_two);
1031 avl_iter_begin(&one_iter, implied_one, FORWARD);
1032 avl_iter_begin(&two_iter, implied_two, FORWARD);
1034 for (;;) {
1035 if (!one_iter.sm && !two_iter.sm)
1036 break;
1037 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
1038 sm_msg("error: Internal smatch error.");
1039 avl_iter_next(&one_iter);
1040 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
1041 if (one_iter.sm != two_iter.sm) {
1042 one_iter.sm->pool = implied_one_slist;
1043 two_iter.sm->pool = implied_two_slist;
1045 tmp_sm = merge_sm_states(one_iter.sm, two_iter.sm);
1046 avl_insert(&results, tmp_sm);
1047 avl_iter_next(&one_iter);
1048 avl_iter_next(&two_iter);
1049 } else {
1050 sm_msg("error: Internal smatch error.");
1051 avl_iter_next(&two_iter);
1055 free_stree(to);
1056 *to = results;
1060 * filter_slist() removes any sm states "slist" holds in common with "filter"
1062 void filter_slist(struct state_list **slist, struct state_list *filter)
1064 struct sm_state *one_sm, *two_sm;
1065 struct state_list *results = NULL;
1067 PREPARE_PTR_LIST(*slist, one_sm);
1068 PREPARE_PTR_LIST(filter, two_sm);
1069 for (;;) {
1070 if (!one_sm && !two_sm)
1071 break;
1072 if (cmp_tracker(one_sm, two_sm) < 0) {
1073 add_ptr_list(&results, one_sm);
1074 NEXT_PTR_LIST(one_sm);
1075 } else if (cmp_tracker(one_sm, two_sm) == 0) {
1076 if (one_sm != two_sm)
1077 add_ptr_list(&results, one_sm);
1078 NEXT_PTR_LIST(one_sm);
1079 NEXT_PTR_LIST(two_sm);
1080 } else {
1081 NEXT_PTR_LIST(two_sm);
1084 FINISH_PTR_LIST(two_sm);
1085 FINISH_PTR_LIST(one_sm);
1087 free_slist(slist);
1088 *slist = results;
1091 void filter_stree(struct AVL **stree, struct AVL *filter)
1093 struct AVL *results = NULL;
1094 AvlIter one_iter;
1095 AvlIter two_iter;
1097 avl_iter_begin(&one_iter, *stree, FORWARD);
1098 avl_iter_begin(&two_iter, filter, FORWARD);
1100 /* FIXME: This should probably be re-written with trees in mind */
1102 for (;;) {
1103 if (!one_iter.sm && !two_iter.sm)
1104 break;
1105 if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
1106 avl_insert(&results, one_iter.sm);
1107 avl_iter_next(&one_iter);
1108 } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
1109 if (one_iter.sm != two_iter.sm)
1110 avl_insert(&results, one_iter.sm);
1111 avl_iter_next(&one_iter);
1112 avl_iter_next(&two_iter);
1113 } else {
1114 avl_iter_next(&two_iter);
1118 free_stree(stree);
1119 *stree = results;
1124 * and_slist_stack() pops the top two slists, overwriting the one with
1125 * the other and pushing it back on the stack.
1127 void and_slist_stack(struct state_list_stack **slist_stack)
1129 struct sm_state *tmp;
1130 struct state_list *right_slist = pop_slist(slist_stack);
1132 FOR_EACH_PTR(right_slist, tmp) {
1133 overwrite_sm_state_stack(slist_stack, tmp);
1134 } END_FOR_EACH_PTR(tmp);
1135 free_slist(&right_slist);
1138 void and_stree_stack(struct stree_stack **stack)
1140 struct sm_state *tmp;
1141 struct AVL *right_stree = pop_stree(stack);
1143 FOR_EACH_SM(right_stree, tmp) {
1144 overwrite_sm_state_stree_stack(stack, tmp);
1145 } END_FOR_EACH_SM(tmp);
1146 free_stree(&right_stree);
1150 * or_slist_stack() is for if we have: if (foo || bar) { foo->baz;
1151 * It pops the two slists from the top of the stack and merges them
1152 * together in a way that preserves the things they have in common
1153 * but creates a merged state for most of the rest.
1154 * You could have code that had: if (foo || foo) { foo->baz;
1155 * It's this function which ensures smatch does the right thing.
1157 void or_slist_stack(struct state_list_stack **pre_conds,
1158 struct state_list *cur_slist,
1159 struct state_list_stack **slist_stack)
1161 struct state_list *new;
1162 struct state_list *old;
1163 struct state_list *pre_slist;
1164 struct state_list *res;
1165 struct state_list *tmp_slist;
1167 new = pop_slist(slist_stack);
1168 old = pop_slist(slist_stack);
1170 pre_slist = pop_slist(pre_conds);
1171 push_slist(pre_conds, clone_slist(pre_slist));
1173 res = clone_slist(pre_slist);
1174 overwrite_slist(old, &res);
1176 tmp_slist = clone_slist(cur_slist);
1177 overwrite_slist(new, &tmp_slist);
1179 merge_slist(&res, tmp_slist);
1180 filter_slist(&res, pre_slist);
1182 push_slist(slist_stack, res);
1183 free_slist(&tmp_slist);
1184 free_slist(&pre_slist);
1185 free_slist(&new);
1186 free_slist(&old);
1189 void or_stree_stack(struct stree_stack **pre_conds,
1190 struct AVL *cur_stree,
1191 struct stree_stack **stack)
1193 struct AVL *new;
1194 struct AVL *old;
1195 struct AVL *pre_stree;
1196 struct AVL *res;
1197 struct AVL *tmp_stree;
1199 new = pop_stree(stack);
1200 old = pop_stree(stack);
1202 pre_stree = pop_stree(pre_conds);
1203 push_stree(pre_conds, avl_clone(pre_stree));
1205 res = avl_clone(pre_stree);
1206 overwrite_stree(old, &res);
1208 tmp_stree = avl_clone(cur_stree);
1209 overwrite_stree(new, &tmp_stree);
1211 merge_stree(&res, tmp_stree);
1212 filter_stree(&res, pre_stree);
1214 push_stree(stack, res);
1215 free_stree(&tmp_stree);
1216 free_stree(&pre_stree);
1217 free_stree(&new);
1218 free_stree(&old);
1222 * get_slist_from_named_stack() is only used for gotos.
1224 struct state_list **get_slist_from_named_stack(struct named_stack *stack,
1225 const char *name)
1227 struct named_slist *tmp;
1229 FOR_EACH_PTR(stack, tmp) {
1230 if (!strcmp(tmp->name, name))
1231 return &tmp->slist;
1232 } END_FOR_EACH_PTR(tmp);
1233 return NULL;
1236 struct AVL **get_named_stree(struct named_stree_stack *stack,
1237 const char *name)
1239 struct named_stree *tmp;
1241 FOR_EACH_PTR(stack, tmp) {
1242 if (!strcmp(tmp->name, name))
1243 return &tmp->stree;
1244 } END_FOR_EACH_PTR(tmp);
1245 return NULL;
1248 /* FIXME: These parameters are in a different order from expected */
1249 void overwrite_slist(struct state_list *from, struct state_list **to)
1251 struct sm_state *tmp;
1253 FOR_EACH_PTR(from, tmp) {
1254 overwrite_sm_state(to, tmp);
1255 } END_FOR_EACH_PTR(tmp);
1258 void overwrite_stree(struct AVL *from, struct AVL **to)
1260 struct sm_state *tmp;
1262 FOR_EACH_SM(from, tmp) {
1263 overwrite_sm_state_stree(to, tmp);
1264 } END_FOR_EACH_SM(tmp);
1267 struct state_list *stree_to_slist(struct AVL *stree)
1269 struct state_list *ret = NULL;
1270 struct sm_state *tmp;
1272 FOR_EACH_SM(stree, tmp) {
1273 overwrite_sm_state(&ret, tmp);
1274 } END_FOR_EACH_SM(tmp);
1276 return ret;
1279 struct AVL *slist_to_stree(struct state_list *slist)
1281 struct AVL *ret = NULL;
1282 struct sm_state *tmp;
1284 FOR_EACH_PTR(slist, tmp) {
1285 overwrite_sm_state_stree(&ret, tmp);
1286 } END_FOR_EACH_PTR(tmp);
1288 return ret;