2 * sparse/smatch_states.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
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];
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
;
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
);
51 static void add_history(struct smatch_state
*state
)
53 struct state_history
*tmp
;
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
;
70 sm_state
->state
= state
;
71 sm_state
->line_history
= NULL
;
72 sm_state
->path_history
= NULL
;
73 add_history(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);
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
);
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
)){
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
)
167 if (state1
== state2
)
169 else if (__has_merge_function(owner
))
170 ret
= __client_merge_function(owner
, name
, sym
, (state1
< state2
?state1
:state2
), (state1
> state2
?state1
:state2
));
174 SM_DEBUG("%d merge name='%s' owner=%d: %d + %d => %d\n",
175 get_lineno(), name
, owner
, state1
, state2
, 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
;
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
) {
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
,
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
,
222 __free_smatch_state(state
);
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
;
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
);
253 } END_FOR_EACH_PTR(tmp
);
254 SM_DEBUG("%d new state. name='%s' owner=%d: %d\n", get_lineno(), name
,
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
;
269 FOR_EACH_PTR(cur_slist
, state
) {
270 if (state
->owner
== owner
&& state
->sym
== sym
271 && !strcmp(state
->name
, name
))
273 } END_FOR_EACH_PTR(state
);
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
);
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,
306 if (!false_stack
|| !true_stack
|| !mini_false_stack
) {
307 printf("Error: missing true/false stacks\n");
311 int tmp
= true_state
;
313 true_state
= false_state
;
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
);
334 del_slist(&cur_slist
);
337 void clear_all_states()
339 struct slist_head
*slist_head
;
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
) {
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
;
398 slist
= pop_slist(&mini_false_stack
);
403 void __pop_false_states_mini()
405 struct state_list
*slist
;
407 slist
= pop_slist(&mini_false_stack
);
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
);
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();
443 slist
= pop_slist(&true_stack
);
448 void __use_false_states()
450 struct state_list
*slist
;
452 push_slist(&true_stack
, clone_slist(cur_slist
));
454 slist
= pop_slist(&false_stack
);
459 void __pop_false_states()
461 struct state_list
*slist
;
463 slist
= pop_slist(&false_stack
);
467 void __merge_false_states()
469 struct state_list
*slist
;
471 slist
= pop_slist(&false_stack
);
476 void __merge_true_states()
478 struct state_list
*slist
;
480 slist
= pop_slist(&true_stack
);
485 void __pop_true_states()
487 struct state_list
*slist
;
489 slist
= pop_slist(&true_stack
);
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
);
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
);
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
);
551 struct state_list
*slist
;
553 slist
= pop_slist(&break_stack
);
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
);
568 push_slist(&switch_stack
, slist
);
571 void __pop_switches()
573 struct state_list
*slist
;
575 slist
= pop_slist(&switch_stack
);
579 void __push_default()
581 push_slist(&default_stack
, NULL
);
582 set_state_stack(&default_stack
, "has_default", 0, NULL
, 0);
587 set_state_stack(&default_stack
, "has_default", 0, NULL
, 1);
592 struct state_list
*slist
;
593 struct smatch_state
*state
;
596 slist
= pop_slist(&default_stack
);
597 FOR_EACH_PTR(slist
, state
) {
598 if (!strcmp(state
->name
, "has_default"))
600 } END_FOR_EACH_PTR(state
);
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
;
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
))
622 } END_FOR_EACH_PTR(tmp
);
626 void __save_gotos(const char *name
)
628 struct state_list
*slist
;
630 slist
= get_slist_from_slist_stack(name
);
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
);
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
);