27 *
28 * So the smatch_flow.c understands code but it doesn't understand states.
29 * smatch_flow calls functions in this file. This file calls functions
30 * in smatch_slist.c which just has boring generic plumbing for handling
31 * state lists. But really it's this file where all the magic happens.
32 */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include "smatch.h"
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
39
40 struct smatch_state undefined = { .name = "undefined" };
41 struct smatch_state ghost = { .name = "ghost" };
42 struct smatch_state merged = { .name = "merged" };
43 struct smatch_state true_state = { .name = "true" };
44 struct smatch_state false_state = { .name = "false" };
45
46 static struct stree *cur_stree; /* current states */
47
48 static struct stree_stack *true_stack; /* states after a t/f branch */
49 static struct stree_stack *false_stack;
50 static struct stree_stack *pre_cond_stack; /* states before a t/f branch */
51
52 static struct stree_stack *cond_true_stack; /* states affected by a branch */
53 static struct stree_stack *cond_false_stack;
54
55 static struct stree_stack *fake_cur_stree_stack;
56 static int read_only;
57
58 static struct stree_stack *break_stack;
59 static struct stree_stack *fake_break_stack;
60 static struct stree_stack *switch_stack;
61 static struct range_list_stack *remaining_cases;
62 static struct stree_stack *default_stack;
63 static struct stree_stack *continue_stack;
64
65 static struct named_stree_stack *goto_stack;
66
67 static struct ptr_list *backup;
68
69 int option_debug;
70
71 void __print_cur_stree(void)
72 {
73 __print_stree(cur_stree);
74 }
75
76 int unreachable(void)
77 {
78 if (!cur_stree)
79 return 1;
80 return 0;
81 }
82
83 struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
84 {
85 struct sm_state *ret;
86
87 if (!name || !state)
88 return NULL;
89
90 if (read_only)
91 sm_perror("cur_stree is read only.");
92
93 if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
94 struct smatch_state *s;
95
96 s = __get_state(owner, name, sym);
97 if (!s)
98 sm_msg("%s new [%s] '%s' %s", __func__,
99 check_name(owner), name, show_state(state));
100 else
101 sm_msg("%s change [%s] '%s' %s => %s",
102 __func__, check_name(owner), name, show_state(s),
113
114 return ret;
115 }
116
117 struct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state)
118 {
119 char *name;
120 struct symbol *sym;
121 struct sm_state *ret = NULL;
122
123 expr = strip_expr(expr);
124 name = expr_to_var_sym(expr, &sym);
125 if (!name || !sym)
126 goto free;
127 ret = set_state(owner, name, sym, state);
128 free:
129 free_string(name);
130 return ret;
131 }
132
133 void __swap_cur_stree(struct stree *stree)
134 {
135 free_stree(&cur_stree);
136 cur_stree = stree;
137 }
138
139 void __push_fake_cur_stree(void)
140 {
141 push_stree(&fake_cur_stree_stack, NULL);
142 __save_pre_cond_states();
143 }
144
145 struct stree *__pop_fake_cur_stree(void)
146 {
147 if (!fake_cur_stree_stack)
148 sm_perror("popping too many fake cur strees.");
149 __use_pre_cond_states();
150 return pop_stree(&fake_cur_stree_stack);
151 }
152
153 void __free_fake_cur_stree(void)
154 {
155 struct stree *stree;
156
157 stree = __pop_fake_cur_stree();
158 free_stree(&stree);
159 }
160
161 void __set_fake_cur_stree_fast(struct stree *stree)
162 {
163 push_stree(&pre_cond_stack, cur_stree);
164 cur_stree = stree;
165 read_only = 1;
166 }
167
168 void __pop_fake_cur_stree_fast(void)
169 {
170 cur_stree = pop_stree(&pre_cond_stack);
171 read_only = 0;
172 }
173
174 void __merge_stree_into_cur(struct stree *stree)
175 {
176 struct sm_state *sm;
177 struct sm_state *orig;
178 struct sm_state *merged;
179
180 FOR_EACH_SM(stree, sm) {
181 orig = get_sm_state(sm->owner, sm->name, sm->sym);
182 if (orig)
183 merged = merge_sm_states(orig, sm);
184 else
185 merged = sm;
186 __set_sm(merged);
187 } END_FOR_EACH_SM(sm);
188 }
189
190 void __set_sm(struct sm_state *sm)
191 {
272 }
273
274 static void call_get_state_hooks(int owner, const char *name, struct symbol *sym)
275 {
276 static int recursion;
277 get_state_hook **fn;
278
279 if (recursion)
280 return;
281 recursion = 1;
282
283 FOR_EACH_PTR(get_state_hooks, fn) {
284 (*fn)(owner, name, sym);
285 } END_FOR_EACH_PTR(fn);
286
287 recursion = 0;
288 }
289
290 struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
291 {
292 return get_state_stree(cur_stree, owner, name, sym);
293 }
294
295 struct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
296 {
297 call_get_state_hooks(owner, name, sym);
298
299 return __get_state(owner, name, sym);
300 }
301
302 struct smatch_state *get_state_expr(int owner, struct expression *expr)
303 {
304 char *name;
305 struct symbol *sym;
306 struct smatch_state *ret = NULL;
307
308 expr = strip_expr(expr);
309 name = expr_to_var_sym(expr, &sym);
310 if (!name || !sym)
311 goto free;
312 ret = get_state(owner, name, sym);
326 }
327
328 struct state_list *get_possible_states_expr(int owner, struct expression *expr)
329 {
330 char *name;
331 struct symbol *sym;
332 struct state_list *ret = NULL;
333
334 expr = strip_expr(expr);
335 name = expr_to_var_sym(expr, &sym);
336 if (!name || !sym)
337 goto free;
338 ret = get_possible_states(owner, name, sym);
339 free:
340 free_string(name);
341 return ret;
342 }
343
344 struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
345 {
346 return get_sm_state_stree(cur_stree, owner, name, sym);
347 }
348
349 struct sm_state *get_sm_state_expr(int owner, struct expression *expr)
350 {
351 char *name;
352 struct symbol *sym;
353 struct sm_state *ret = NULL;
354
355 expr = strip_expr(expr);
356 name = expr_to_var_sym(expr, &sym);
357 if (!name || !sym)
358 goto free;
359 ret = get_sm_state(owner, name, sym);
360 free:
361 free_string(name);
362 return ret;
363 }
364
365 void delete_state(int owner, const char *name, struct symbol *sym)
576 set_state(-1, "unnull_path", NULL, &true_state);
577 }
578
579 int __path_is_null(void)
580 {
581 if (cur_stree)
582 return 0;
583 return 1;
584 }
585
586 static void check_stree_stack_free(struct stree_stack **stack)
587 {
588 if (*stack) {
589 sm_perror("stack not empty");
590 free_stack_and_strees(stack);
591 }
592 }
593
594 void save_all_states(void)
595 {
596 __add_ptr_list(&backup, cur_stree, 0);
597 cur_stree = NULL;
598
599 __add_ptr_list(&backup, true_stack, 0);
600 true_stack = NULL;
601 __add_ptr_list(&backup, false_stack, 0);
602 false_stack = NULL;
603 __add_ptr_list(&backup, pre_cond_stack, 0);
604 pre_cond_stack = NULL;
605
606 __add_ptr_list(&backup, cond_true_stack, 0);
607 cond_true_stack = NULL;
608 __add_ptr_list(&backup, cond_false_stack, 0);
609 cond_false_stack = NULL;
610
611 __add_ptr_list(&backup, fake_cur_stree_stack, 0);
612 fake_cur_stree_stack = NULL;
613
614 __add_ptr_list(&backup, break_stack, 0);
615 break_stack = NULL;
616 __add_ptr_list(&backup, fake_break_stack, 0);
617 fake_break_stack = NULL;
618
619 __add_ptr_list(&backup, switch_stack, 0);
620 switch_stack = NULL;
621 __add_ptr_list(&backup, remaining_cases, 0);
622 remaining_cases = NULL;
623 __add_ptr_list(&backup, default_stack, 0);
624 default_stack = NULL;
625 __add_ptr_list(&backup, continue_stack, 0);
626 continue_stack = NULL;
627
628 __add_ptr_list(&backup, goto_stack, 0);
629 goto_stack = NULL;
630 }
631
632 static void *pop_backup(void)
633 {
634 void *ret;
635
636 ret = last_ptr_list(backup);
637 delete_ptr_list_last(&backup);
638 return ret;
639 }
640
641 void restore_all_states(void)
642 {
643 goto_stack = pop_backup();
644
645 continue_stack = pop_backup();
646 default_stack = pop_backup();
647 remaining_cases = pop_backup();
648 switch_stack = pop_backup();
|
27 *
28 * So the smatch_flow.c understands code but it doesn't understand states.
29 * smatch_flow calls functions in this file. This file calls functions
30 * in smatch_slist.c which just has boring generic plumbing for handling
31 * state lists. But really it's this file where all the magic happens.
32 */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include "smatch.h"
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
39
40 struct smatch_state undefined = { .name = "undefined" };
41 struct smatch_state ghost = { .name = "ghost" };
42 struct smatch_state merged = { .name = "merged" };
43 struct smatch_state true_state = { .name = "true" };
44 struct smatch_state false_state = { .name = "false" };
45
46 static struct stree *cur_stree; /* current states */
47 static struct stree *fast_overlay;
48
49 static struct stree_stack *true_stack; /* states after a t/f branch */
50 static struct stree_stack *false_stack;
51 static struct stree_stack *pre_cond_stack; /* states before a t/f branch */
52
53 static struct stree_stack *cond_true_stack; /* states affected by a branch */
54 static struct stree_stack *cond_false_stack;
55
56 static struct stree_stack *fake_cur_stree_stack;
57 static int read_only;
58
59 static struct stree_stack *break_stack;
60 static struct stree_stack *fake_break_stack;
61 static struct stree_stack *switch_stack;
62 static struct range_list_stack *remaining_cases;
63 static struct stree_stack *default_stack;
64 static struct stree_stack *continue_stack;
65
66 static struct named_stree_stack *goto_stack;
67
68 static struct ptr_list *backup;
69
70 int option_debug;
71
72 void __print_cur_stree(void)
73 {
74 __print_stree(cur_stree);
75 }
76
77 int unreachable(void)
78 {
79 if (!cur_stree)
80 return 1;
81 return 0;
82 }
83
84 void __set_cur_stree_readonly(void)
85 {
86 read_only++;
87 }
88
89 void __set_cur_stree_writable(void)
90 {
91 read_only--;
92 }
93
94 struct sm_state *set_state(int owner, const char *name, struct symbol *sym, struct smatch_state *state)
95 {
96 struct sm_state *ret;
97
98 if (!name || !state)
99 return NULL;
100
101 if (read_only)
102 sm_perror("cur_stree is read only.");
103
104 if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
105 struct smatch_state *s;
106
107 s = __get_state(owner, name, sym);
108 if (!s)
109 sm_msg("%s new [%s] '%s' %s", __func__,
110 check_name(owner), name, show_state(state));
111 else
112 sm_msg("%s change [%s] '%s' %s => %s",
113 __func__, check_name(owner), name, show_state(s),
124
125 return ret;
126 }
127
128 struct sm_state *set_state_expr(int owner, struct expression *expr, struct smatch_state *state)
129 {
130 char *name;
131 struct symbol *sym;
132 struct sm_state *ret = NULL;
133
134 expr = strip_expr(expr);
135 name = expr_to_var_sym(expr, &sym);
136 if (!name || !sym)
137 goto free;
138 ret = set_state(owner, name, sym, state);
139 free:
140 free_string(name);
141 return ret;
142 }
143
144 struct stree *__swap_cur_stree(struct stree *stree)
145 {
146 struct stree *orig = cur_stree;
147
148 cur_stree = stree;
149 return orig;
150 }
151
152 void __push_fake_cur_stree(void)
153 {
154 push_stree(&fake_cur_stree_stack, NULL);
155 __save_pre_cond_states();
156 }
157
158 struct stree *__pop_fake_cur_stree(void)
159 {
160 if (!fake_cur_stree_stack)
161 sm_perror("popping too many fake cur strees.");
162 __use_pre_cond_states();
163 return pop_stree(&fake_cur_stree_stack);
164 }
165
166 void __free_fake_cur_stree(void)
167 {
168 struct stree *stree;
169
170 stree = __pop_fake_cur_stree();
171 free_stree(&stree);
172 }
173
174 void __set_fake_cur_stree_fast(struct stree *stree)
175 {
176 if (fast_overlay) {
177 sm_perror("cannot nest fast overlay");
178 return;
179 }
180 fast_overlay = stree;
181 set_fast_math_only();
182 }
183
184 void __pop_fake_cur_stree_fast(void)
185 {
186 fast_overlay = NULL;
187 clear_fast_math_only();
188 }
189
190 void __merge_stree_into_cur(struct stree *stree)
191 {
192 struct sm_state *sm;
193 struct sm_state *orig;
194 struct sm_state *merged;
195
196 FOR_EACH_SM(stree, sm) {
197 orig = get_sm_state(sm->owner, sm->name, sm->sym);
198 if (orig)
199 merged = merge_sm_states(orig, sm);
200 else
201 merged = sm;
202 __set_sm(merged);
203 } END_FOR_EACH_SM(sm);
204 }
205
206 void __set_sm(struct sm_state *sm)
207 {
288 }
289
290 static void call_get_state_hooks(int owner, const char *name, struct symbol *sym)
291 {
292 static int recursion;
293 get_state_hook **fn;
294
295 if (recursion)
296 return;
297 recursion = 1;
298
299 FOR_EACH_PTR(get_state_hooks, fn) {
300 (*fn)(owner, name, sym);
301 } END_FOR_EACH_PTR(fn);
302
303 recursion = 0;
304 }
305
306 struct smatch_state *__get_state(int owner, const char *name, struct symbol *sym)
307 {
308 struct sm_state *sm;
309
310 sm = get_sm_state(owner, name, sym);
311 if (!sm)
312 return NULL;
313 return sm->state;
314 }
315
316 struct smatch_state *get_state(int owner, const char *name, struct symbol *sym)
317 {
318 call_get_state_hooks(owner, name, sym);
319
320 return __get_state(owner, name, sym);
321 }
322
323 struct smatch_state *get_state_expr(int owner, struct expression *expr)
324 {
325 char *name;
326 struct symbol *sym;
327 struct smatch_state *ret = NULL;
328
329 expr = strip_expr(expr);
330 name = expr_to_var_sym(expr, &sym);
331 if (!name || !sym)
332 goto free;
333 ret = get_state(owner, name, sym);
347 }
348
349 struct state_list *get_possible_states_expr(int owner, struct expression *expr)
350 {
351 char *name;
352 struct symbol *sym;
353 struct state_list *ret = NULL;
354
355 expr = strip_expr(expr);
356 name = expr_to_var_sym(expr, &sym);
357 if (!name || !sym)
358 goto free;
359 ret = get_possible_states(owner, name, sym);
360 free:
361 free_string(name);
362 return ret;
363 }
364
365 struct sm_state *get_sm_state(int owner, const char *name, struct symbol *sym)
366 {
367 struct sm_state *ret;
368
369 ret = get_sm_state_stree(fast_overlay, owner, name, sym);
370 if (ret)
371 return ret;
372
373 return get_sm_state_stree(cur_stree, owner, name, sym);
374 }
375
376 struct sm_state *get_sm_state_expr(int owner, struct expression *expr)
377 {
378 char *name;
379 struct symbol *sym;
380 struct sm_state *ret = NULL;
381
382 expr = strip_expr(expr);
383 name = expr_to_var_sym(expr, &sym);
384 if (!name || !sym)
385 goto free;
386 ret = get_sm_state(owner, name, sym);
387 free:
388 free_string(name);
389 return ret;
390 }
391
392 void delete_state(int owner, const char *name, struct symbol *sym)
603 set_state(-1, "unnull_path", NULL, &true_state);
604 }
605
606 int __path_is_null(void)
607 {
608 if (cur_stree)
609 return 0;
610 return 1;
611 }
612
613 static void check_stree_stack_free(struct stree_stack **stack)
614 {
615 if (*stack) {
616 sm_perror("stack not empty");
617 free_stack_and_strees(stack);
618 }
619 }
620
621 void save_all_states(void)
622 {
623 __add_ptr_list(&backup, cur_stree);
624 cur_stree = NULL;
625
626 __add_ptr_list(&backup, true_stack);
627 true_stack = NULL;
628 __add_ptr_list(&backup, false_stack);
629 false_stack = NULL;
630 __add_ptr_list(&backup, pre_cond_stack);
631 pre_cond_stack = NULL;
632
633 __add_ptr_list(&backup, cond_true_stack);
634 cond_true_stack = NULL;
635 __add_ptr_list(&backup, cond_false_stack);
636 cond_false_stack = NULL;
637
638 __add_ptr_list(&backup, fake_cur_stree_stack);
639 fake_cur_stree_stack = NULL;
640
641 __add_ptr_list(&backup, break_stack);
642 break_stack = NULL;
643 __add_ptr_list(&backup, fake_break_stack);
644 fake_break_stack = NULL;
645
646 __add_ptr_list(&backup, switch_stack);
647 switch_stack = NULL;
648 __add_ptr_list(&backup, remaining_cases);
649 remaining_cases = NULL;
650 __add_ptr_list(&backup, default_stack);
651 default_stack = NULL;
652 __add_ptr_list(&backup, continue_stack);
653 continue_stack = NULL;
654
655 __add_ptr_list(&backup, goto_stack);
656 goto_stack = NULL;
657 }
658
659 static void *pop_backup(void)
660 {
661 void *ret;
662
663 ret = last_ptr_list(backup);
664 delete_ptr_list_last(&backup);
665 return ret;
666 }
667
668 void restore_all_states(void)
669 {
670 goto_stack = pop_backup();
671
672 continue_stack = pop_backup();
673 default_stack = pop_backup();
674 remaining_cases = pop_backup();
675 switch_stack = pop_backup();
|