constraints: get rid of add_equiv()
[smatch.git] / smatch_slist.c
blob2d0e3f992b34e76f6440fd71b537214a7e751668
1 /*
2 * sparse/smatch_slist.c
4 * Copyright (C) 2008,2009 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"
13 #include "smatch_slist.h"
15 #undef CHECKORDER
17 ALLOCATOR(smatch_state, "smatch state");
18 ALLOCATOR(sm_state, "sm state");
19 ALLOCATOR(named_slist, "named slist");
20 __DO_ALLOCATOR(char, 0, 1, "state names", sname);
22 static int sm_state_counter;
24 char *show_sm(struct sm_state *sm)
26 static char buf[256];
27 struct sm_state *tmp;
28 int pos;
29 int i;
31 pos = snprintf(buf, sizeof(buf), "[%s] '%s' = %s (",
32 check_name(sm->owner), sm->name, show_state(sm->state));
33 if (pos > sizeof(buf))
34 goto truncate;
36 i = 0;
37 FOR_EACH_PTR(sm->possible, tmp) {
38 if (i++)
39 pos += snprintf(buf + pos, sizeof(buf) - pos, ", ");
40 if (pos > sizeof(buf))
41 goto truncate;
42 pos += snprintf(buf + pos, sizeof(buf) - pos, "%s",
43 show_state(tmp->state));
44 if (pos > sizeof(buf))
45 goto truncate;
46 } END_FOR_EACH_PTR(tmp);
47 snprintf(buf + pos, sizeof(buf) - pos, ")");
49 return buf;
51 truncate:
52 for (i = 0; i < 3; i++)
53 buf[sizeof(buf) - 2 - i] = '.';
54 return buf;
57 void __print_slist(struct state_list *slist)
59 struct sm_state *sm;
61 printf("dumping slist at %d\n", get_lineno());
62 FOR_EACH_PTR(slist, sm) {
63 printf("%s\n", show_sm(sm));
64 } END_FOR_EACH_PTR(sm);
65 printf("---\n");
68 /* NULL states go at the end to simplify merge_slist */
69 int cmp_tracker(const struct sm_state *a, const struct sm_state *b)
71 int ret;
73 if (a == b)
74 return 0;
75 if (!b)
76 return -1;
77 if (!a)
78 return 1;
80 if (a->owner > b->owner)
81 return -1;
82 if (a->owner < b->owner)
83 return 1;
85 ret = strcmp(a->name, b->name);
86 if (ret)
87 return ret;
89 if (!b->sym && a->sym)
90 return -1;
91 if (!a->sym && b->sym)
92 return 1;
93 if (a->sym > b->sym)
94 return -1;
95 if (a->sym < b->sym)
96 return 1;
98 return 0;
101 static int cmp_sm_states(const struct sm_state *a, const struct sm_state *b)
103 int ret;
105 ret = cmp_tracker(a, b);
106 if (ret)
107 return ret;
109 /* todo: add hook for smatch_extra.c */
110 if (a->state > b->state)
111 return -1;
112 if (a->state < b->state)
113 return 1;
114 return 0;
117 static struct sm_state *alloc_sm_state(int owner, const char *name,
118 struct symbol *sym, struct smatch_state *state)
120 struct sm_state *sm_state = __alloc_sm_state(0);
122 sm_state_counter++;
124 sm_state->name = alloc_sname(name);
125 sm_state->owner = owner;
126 sm_state->sym = sym;
127 sm_state->state = state;
128 sm_state->line = get_lineno();
129 sm_state->merged = 0;
130 sm_state->implied = 0;
131 sm_state->pool = NULL;
132 sm_state->left = NULL;
133 sm_state->right = NULL;
134 sm_state->nr_children = 1;
135 sm_state->possible = NULL;
136 add_ptr_list(&sm_state->possible, sm_state);
137 return sm_state;
140 static struct sm_state *alloc_state_no_name(int owner, const char *name,
141 struct symbol *sym,
142 struct smatch_state *state)
144 struct sm_state *tmp;
146 tmp = alloc_sm_state(owner, NULL, sym, state);
147 tmp->name = name;
148 return tmp;
151 void add_sm_state_slist(struct state_list **slist, struct sm_state *new)
153 struct sm_state *tmp;
155 FOR_EACH_PTR(*slist, tmp) {
156 if (cmp_sm_states(tmp, new) < 0)
157 continue;
158 else if (cmp_sm_states(tmp, new) == 0) {
159 return;
160 } else {
161 INSERT_CURRENT(new, tmp);
162 return;
164 } END_FOR_EACH_PTR(tmp);
165 add_ptr_list(slist, new);
168 static void copy_possibles(struct sm_state *to, struct sm_state *from)
170 struct sm_state *tmp;
171 struct sm_state *tmp2;
173 FOR_EACH_PTR(from->possible, tmp) {
174 tmp2 = alloc_state_no_name(tmp->owner, tmp->name, tmp->sym,
175 tmp->state);
176 tmp2->line = tmp->line;
177 add_sm_state_slist(&to->possible, tmp2);
178 } END_FOR_EACH_PTR(tmp);
181 char *alloc_sname(const char *str)
183 char *tmp;
185 if (!str)
186 return NULL;
187 tmp = __alloc_sname(strlen(str) + 1);
188 strcpy(tmp, str);
189 return tmp;
192 int out_of_memory()
195 * I decided to use 50M here based on trial and error.
196 * It works out OK for the kernel and so it should work
197 * for most other projects as well.
199 if (sm_state_counter * sizeof(struct sm_state) >= 50000000)
200 return 1;
201 return 0;
204 static void free_sm_state(struct sm_state *sm)
206 free_slist(&sm->possible);
208 * fixme. Free the actual state.
209 * Right now we leave it until the end of the function
210 * because we don't want to double free it.
211 * Use the freelist to not double free things
215 static void free_all_sm_states(struct allocation_blob *blob)
217 unsigned int size = sizeof(struct sm_state);
218 unsigned int offset = 0;
220 while (offset < blob->offset) {
221 free_sm_state((struct sm_state *)(blob->data + offset));
222 offset += size;
226 /* At the end of every function we free all the sm_states */
227 void free_every_single_sm_state(void)
229 struct allocator_struct *desc = &sm_state_allocator;
230 struct allocation_blob *blob = desc->blobs;
232 desc->blobs = NULL;
233 desc->allocations = 0;
234 desc->total_bytes = 0;
235 desc->useful_bytes = 0;
236 desc->freelist = NULL;
237 while (blob) {
238 struct allocation_blob *next = blob->next;
239 free_all_sm_states(blob);
240 blob_free(blob, desc->chunking);
241 blob = next;
243 clear_sname_alloc();
245 sm_state_counter = 0;
248 struct sm_state *clone_sm(struct sm_state *s)
250 struct sm_state *ret;
252 ret = alloc_state_no_name(s->owner, s->name, s->sym, s->state);
253 ret->merged = s->merged;
254 ret->implied = s->implied;
255 ret->line = s->line;
256 /* clone_sm() doesn't copy the pools. Each state needs to have
257 only one pool. */
258 ret->possible = clone_slist(s->possible);
259 ret->left = s->left;
260 ret->right = s->right;
261 ret->nr_children = s->nr_children;
262 return ret;
265 int is_merged(struct sm_state *sm)
267 return sm->merged;
270 int is_implied(struct sm_state *sm)
272 return sm->implied;
275 int slist_has_state(struct state_list *slist, struct smatch_state *state)
277 struct sm_state *tmp;
279 FOR_EACH_PTR(slist, tmp) {
280 if (tmp->state == state)
281 return 1;
282 } END_FOR_EACH_PTR(tmp);
283 return 0;
286 static void check_order(struct state_list *slist)
288 #ifdef CHECKORDER
289 struct sm_state *sm;
290 struct sm_state *last = NULL;
291 int printed = 0;
293 FOR_EACH_PTR(slist, sm) {
294 if (last && cmp_tracker(sm, last) <= 0) {
295 printf("Error. Unsorted slist %d vs %d, %p vs %p, "
296 "%s vs %s\n", last->owner, sm->owner,
297 last->sym, sm->sym, last->name, sm->name);
298 printed = 1;
300 last = state;
301 } END_FOR_EACH_PTR(sm);
303 if (printed)
304 printf("======\n");
305 #endif
308 struct state_list *clone_slist(struct state_list *from_slist)
310 struct sm_state *sm;
311 struct state_list *to_slist = NULL;
313 FOR_EACH_PTR(from_slist, sm) {
314 add_ptr_list(&to_slist, sm);
315 } END_FOR_EACH_PTR(sm);
316 check_order(to_slist);
317 return to_slist;
320 struct state_list_stack *clone_stack(struct state_list_stack *from_stack)
322 struct state_list *slist;
323 struct state_list_stack *to_stack = NULL;
325 FOR_EACH_PTR(from_stack, slist) {
326 push_slist(&to_stack, slist);
327 } END_FOR_EACH_PTR(slist);
328 return to_stack;
331 struct smatch_state *merge_states(int owner, const char *name,
332 struct symbol *sym,
333 struct smatch_state *state1,
334 struct smatch_state *state2)
336 struct smatch_state *ret;
338 if (state1 == state2)
339 ret = state1;
340 else if (__has_merge_function(owner))
341 ret = __client_merge_function(owner, name, sym, state1, state2);
342 else if (!state1 || !state2)
343 ret = &undefined;
344 else
345 ret = &merged;
346 return ret;
349 struct sm_state *merge_sm_states(struct sm_state *one, struct sm_state *two)
351 struct smatch_state *s;
352 struct sm_state *result;
354 if (one == two)
355 return one;
356 s = merge_states(one->owner, one->name, one->sym, one->state, two->state);
357 result = alloc_state_no_name(one->owner, one->name, one->sym, s);
358 result->merged = 1;
359 result->left = one;
360 result->right = two;
361 result->nr_children = one->nr_children + two->nr_children;
362 copy_possibles(result, one);
363 copy_possibles(result, two);
365 if (option_debug) {
366 struct sm_state *tmp;
367 int i = 0;
369 printf("%d merge name='%s' [%s] %s(L %d) + %s(L %d) => %s (",
370 get_lineno(), one->name, check_name(one->owner),
371 show_state(one->state), one->line,
372 show_state(two->state), two->line,
373 show_state(s));
375 FOR_EACH_PTR(result->possible, tmp) {
376 if (i++)
377 printf(", ");
378 printf("%s", show_state(tmp->state));
379 } END_FOR_EACH_PTR(tmp);
380 printf(")\n");
383 return result;
386 struct sm_state *get_sm_state_slist(struct state_list *slist, int owner, const char *name,
387 struct symbol *sym)
389 struct sm_state *sm;
391 if (!name)
392 return NULL;
394 FOR_EACH_PTR(slist, sm) {
395 if (sm->owner == owner && sm->sym == sym && !strcmp(sm->name, name))
396 return sm;
397 } END_FOR_EACH_PTR(sm);
398 return NULL;
401 struct smatch_state *get_state_slist(struct state_list *slist,
402 int owner, const char *name,
403 struct symbol *sym)
405 struct sm_state *sm;
407 sm = get_sm_state_slist(slist, owner, name, sym);
408 if (sm)
409 return sm->state;
410 return NULL;
413 void overwrite_sm_state(struct state_list **slist, struct sm_state *new)
415 struct sm_state *tmp;
417 FOR_EACH_PTR(*slist, tmp) {
418 if (cmp_tracker(tmp, new) < 0)
419 continue;
420 else if (cmp_tracker(tmp, new) == 0) {
421 REPLACE_CURRENT_PTR(tmp, new);
422 return;
423 } else {
424 INSERT_CURRENT(new, tmp);
425 return;
427 } END_FOR_EACH_PTR(tmp);
428 add_ptr_list(slist, new);
431 void overwrite_sm_state_stack(struct state_list_stack **stack,
432 struct sm_state *sm)
434 struct state_list *slist;
436 slist = pop_slist(stack);
437 overwrite_sm_state(&slist, sm);
438 push_slist(stack, slist);
441 struct sm_state *set_state_slist(struct state_list **slist, int owner, const char *name,
442 struct symbol *sym, struct smatch_state *state)
444 struct sm_state *tmp;
445 struct sm_state *new = alloc_sm_state(owner, name, sym, state);
447 FOR_EACH_PTR(*slist, tmp) {
448 if (cmp_tracker(tmp, new) < 0)
449 continue;
450 else if (cmp_tracker(tmp, new) == 0) {
451 REPLACE_CURRENT_PTR(tmp, new);
452 return new;
453 } else {
454 INSERT_CURRENT(new, tmp);
455 return new;
457 } END_FOR_EACH_PTR(tmp);
458 add_ptr_list(slist, new);
459 return new;
462 void delete_state_slist(struct state_list **slist, int owner, const char *name,
463 struct symbol *sym)
465 struct sm_state *sm;
467 FOR_EACH_PTR(*slist, sm) {
468 if (sm->owner == owner && sm->sym == sym && !strcmp(sm->name, name)) {
469 DELETE_CURRENT_PTR(sm);
470 return;
472 } END_FOR_EACH_PTR(sm);
475 void delete_state_stack(struct state_list_stack **stack, int owner, const char *name,
476 struct symbol *sym)
478 struct state_list *slist;
480 slist = pop_slist(stack);
481 delete_state_slist(&slist, owner, name, sym);
482 push_slist(stack, slist);
485 void push_slist(struct state_list_stack **list_stack, struct state_list *slist)
487 add_ptr_list(list_stack, slist);
490 struct state_list *pop_slist(struct state_list_stack **list_stack)
492 struct state_list *slist;
494 slist = last_ptr_list((struct ptr_list *)*list_stack);
495 delete_ptr_list_last((struct ptr_list **)list_stack);
496 return slist;
499 void free_slist(struct state_list **slist)
501 __free_ptr_list((struct ptr_list **)slist);
504 void free_stack(struct state_list_stack **stack)
506 __free_ptr_list((struct ptr_list **)stack);
509 void free_stack_and_slists(struct state_list_stack **slist_stack)
511 struct state_list *slist;
513 FOR_EACH_PTR(*slist_stack, slist) {
514 free_slist(&slist);
515 } END_FOR_EACH_PTR(slist);
516 free_stack(slist_stack);
520 * set_state_stack() sets the state for the top slist on the stack.
522 struct sm_state *set_state_stack(struct state_list_stack **stack, int owner, const char *name,
523 struct symbol *sym, struct smatch_state *state)
525 struct state_list *slist;
526 struct sm_state *sm;
528 slist = pop_slist(stack);
529 sm = set_state_slist(&slist, owner, name, sym, state);
530 push_slist(stack, slist);
532 return sm;
536 * get_sm_state_stack() gets the state for the top slist on the stack.
538 struct sm_state *get_sm_state_stack(struct state_list_stack *stack,
539 int owner, const char *name,
540 struct symbol *sym)
542 struct state_list *slist;
543 struct sm_state *ret;
545 slist = pop_slist(&stack);
546 ret = get_sm_state_slist(slist, owner, name, sym);
547 push_slist(&stack, slist);
548 return ret;
551 struct smatch_state *get_state_stack(struct state_list_stack *stack,
552 int owner, const char *name,
553 struct symbol *sym)
555 struct sm_state *sm;
557 sm = get_sm_state_stack(stack, owner, name, sym);
558 if (sm)
559 return sm->state;
560 return NULL;
563 static void match_states(struct state_list **one, struct state_list **two)
565 struct sm_state *one_sm;
566 struct sm_state *two_sm;
567 struct sm_state *tmp;
568 struct smatch_state *tmp_state;
569 struct state_list *add_to_one = NULL;
570 struct state_list *add_to_two = NULL;
572 PREPARE_PTR_LIST(*one, one_sm);
573 PREPARE_PTR_LIST(*two, two_sm);
574 for (;;) {
575 if (!one_sm && !two_sm)
576 break;
577 if (cmp_tracker(one_sm, two_sm) < 0) {
578 tmp_state = __client_unmatched_state_function(one_sm);
579 tmp = alloc_state_no_name(one_sm->owner, one_sm->name,
580 one_sm->sym, tmp_state);
581 add_ptr_list(&add_to_two, tmp);
582 NEXT_PTR_LIST(one_sm);
583 } else if (cmp_tracker(one_sm, two_sm) == 0) {
584 NEXT_PTR_LIST(one_sm);
585 NEXT_PTR_LIST(two_sm);
586 } else {
587 tmp_state = __client_unmatched_state_function(two_sm);
588 tmp = alloc_state_no_name(two_sm->owner, two_sm->name,
589 two_sm->sym, tmp_state);
590 add_ptr_list(&add_to_one, tmp);
591 NEXT_PTR_LIST(two_sm);
594 FINISH_PTR_LIST(two_sm);
595 FINISH_PTR_LIST(one_sm);
597 overwrite_slist(add_to_one, one);
598 overwrite_slist(add_to_two, two);
601 static void clone_pool_havers(struct state_list *slist)
603 struct sm_state *sm;
604 struct sm_state *new;
606 FOR_EACH_PTR(slist, sm) {
607 if (sm->pool) {
608 new = clone_sm(sm);
609 REPLACE_CURRENT_PTR(sm, new);
611 } END_FOR_EACH_PTR(sm);
615 * merge_slist() is called whenever paths merge, such as after
616 * an if statement. It takes the two slists and creates one.
618 void merge_slist(struct state_list **to, struct state_list *slist)
620 struct sm_state *one_sm, *two_sm, *tmp;
621 struct state_list *results = NULL;
622 struct state_list *implied_one = NULL;
623 struct state_list *implied_two = NULL;
625 if (out_of_memory())
626 return;
628 check_order(*to);
629 check_order(slist);
631 /* merging a null and nonnull path gives you only the nonnull path */
632 if (!slist)
633 return;
635 if (!*to) {
636 *to = clone_slist(slist);
637 return;
640 implied_one = clone_slist(*to);
641 implied_two = clone_slist(slist);
643 match_states(&implied_one, &implied_two);
645 clone_pool_havers(implied_one);
646 clone_pool_havers(implied_two);
648 PREPARE_PTR_LIST(implied_one, one_sm);
649 PREPARE_PTR_LIST(implied_two, two_sm);
650 for (;;) {
651 if (!one_sm && !two_sm)
652 break;
653 if (cmp_tracker(one_sm, two_sm) < 0) {
654 sm_msg("error: Internal smatch error.");
655 NEXT_PTR_LIST(one_sm);
656 } else if (cmp_tracker(one_sm, two_sm) == 0) {
657 if (one_sm != two_sm) {
658 one_sm->pool = implied_one;
659 two_sm->pool = implied_two;
662 tmp = merge_sm_states(one_sm, two_sm);
663 add_ptr_list(&results, tmp);
664 NEXT_PTR_LIST(one_sm);
665 NEXT_PTR_LIST(two_sm);
666 } else {
667 sm_msg("error: Internal smatch error.");
668 NEXT_PTR_LIST(two_sm);
671 FINISH_PTR_LIST(two_sm);
672 FINISH_PTR_LIST(one_sm);
674 free_slist(to);
675 *to = results;
679 * filter_slist() removes any sm states "slist" holds in common with "filter"
681 void filter_slist(struct state_list **slist, struct state_list *filter)
683 struct sm_state *one_sm, *two_sm;
684 struct state_list *results = NULL;
686 PREPARE_PTR_LIST(*slist, one_sm);
687 PREPARE_PTR_LIST(filter, two_sm);
688 for (;;) {
689 if (!one_sm && !two_sm)
690 break;
691 if (cmp_tracker(one_sm, two_sm) < 0) {
692 add_ptr_list(&results, one_sm);
693 NEXT_PTR_LIST(one_sm);
694 } else if (cmp_tracker(one_sm, two_sm) == 0) {
695 if (one_sm != two_sm)
696 add_ptr_list(&results, one_sm);
697 NEXT_PTR_LIST(one_sm);
698 NEXT_PTR_LIST(two_sm);
699 } else {
700 NEXT_PTR_LIST(two_sm);
703 FINISH_PTR_LIST(two_sm);
704 FINISH_PTR_LIST(one_sm);
706 free_slist(slist);
707 *slist = results;
711 * and_slist_stack() pops the top two slists, overwriting the one with
712 * the other and pushing it back on the stack.
714 void and_slist_stack(struct state_list_stack **slist_stack)
716 struct sm_state *tmp;
717 struct state_list *right_slist = pop_slist(slist_stack);
719 FOR_EACH_PTR(right_slist, tmp) {
720 overwrite_sm_state_stack(slist_stack, tmp);
721 } END_FOR_EACH_PTR(tmp);
722 free_slist(&right_slist);
726 * or_slist_stack() is for if we have: if (foo || bar) { foo->baz;
727 * It pops the two slists from the top of the stack and merges them
728 * together in a way that preserves the things they have in common
729 * but creates a merged state for most of the rest.
730 * You could have code that had: if (foo || foo) { foo->baz;
731 * It's this function which ensures smatch does the right thing.
733 void or_slist_stack(struct state_list_stack **pre_conds,
734 struct state_list *cur_slist,
735 struct state_list_stack **slist_stack)
737 struct state_list *new;
738 struct state_list *old;
739 struct state_list *pre_slist;
740 struct state_list *res;
741 struct state_list *tmp_slist;
743 new = pop_slist(slist_stack);
744 old = pop_slist(slist_stack);
746 pre_slist = pop_slist(pre_conds);
747 push_slist(pre_conds, clone_slist(pre_slist));
749 res = clone_slist(pre_slist);
750 overwrite_slist(old, &res);
752 tmp_slist = clone_slist(cur_slist);
753 overwrite_slist(new, &tmp_slist);
755 merge_slist(&res, tmp_slist);
756 filter_slist(&res, pre_slist);
758 push_slist(slist_stack, res);
759 free_slist(&tmp_slist);
760 free_slist(&pre_slist);
761 free_slist(&new);
762 free_slist(&old);
766 * get_slist_from_named_stack() is only used for gotos.
768 struct state_list **get_slist_from_named_stack(struct named_stack *stack,
769 const char *name)
771 struct named_slist *tmp;
773 FOR_EACH_PTR(stack, tmp) {
774 if (!strcmp(tmp->name, name))
775 return &tmp->slist;
776 } END_FOR_EACH_PTR(tmp);
777 return NULL;
780 void overwrite_slist(struct state_list *from, struct state_list **to)
782 struct sm_state *tmp;
784 FOR_EACH_PTR(from, tmp) {
785 overwrite_sm_state(to, tmp);
786 } END_FOR_EACH_PTR(tmp);