2 * sparse/smatch_implied.c
4 * Copyright (C) 2008 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
11 * Imagine we have this code:
18 * if (foo == 99) // <-- point #2
19 * bar->baz; // <-- point #3
22 * At point #3 bar is non null and can be dereferenced.
24 * It's smatch_implied.c which sets bar to non null at point #2.
26 * At point #1 merge_slist() stores the list of states from both
27 * the true and false paths. On the true path foo == 99 and on
28 * the false path foo == 1. merge_slist() sets their my_pools
29 * list to show the other states which were there when foo == 99.
31 * When it comes to the if (foo == 99) the smatch implied hook
32 * looks for all the pools where foo was not 99. It makes a list
35 * Then for bar (and all the other states) it says, ok bar is a
36 * merged state that came from these previous states. We'll
37 * chop out all the states where it came from a pool where
38 * foo != 99 and merge it all back together.
40 * That is the implied state of bar.
42 * merge_slist() sets up ->my_pools.
43 * merge_sm_state() sets ->pre_merge.
44 * If an sm_state is not the same on both sides of a merge, it
45 * gets a ->my_pool set for both sides. The result is a merged
46 * state that has it's ->pre_merge pointers set. Merged states
47 * do not immediately have any my_pools set, but maybe will later
48 * when they themselves are merged.
49 * A pool is a list of all the states that were set at the time.
53 #include "smatch_slist.h"
54 #include "smatch_extra.h"
56 int debug_implied_states
= 0;
57 int option_no_implied
= 0;
59 static int pools_overlap(struct state_list_stack
*pools1
,
60 struct state_list_stack
*pools2
)
62 struct state_list
*one
;
63 struct state_list
*two
;
65 PREPARE_PTR_LIST(pools1
, one
);
66 PREPARE_PTR_LIST(pools2
, two
);
73 } else if (one
== two
) {
84 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
85 struct state_list_stack
*pools
, int *modified
)
87 struct sm_state
*ret
= NULL
;
89 struct sm_state
*tmp_keep
;
90 struct state_list
*keep
= NULL
;
92 if (pools_overlap(sm
->my_pools
, pools
)) {
93 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
94 show_state(sm
->state
), sm
->line
);
102 DIMPLIED("checking %s = %s from %d\n", sm
->name
,
103 show_state(sm
->state
), sm
->line
);
104 FOR_EACH_PTR(sm
->pre_merge
, pre
) {
105 tmp_keep
= remove_my_pools(pre
, pools
, &removed
);
107 add_ptr_list(&keep
, tmp_keep
);
108 } END_FOR_EACH_PTR(pre
);
110 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
115 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
119 FOR_EACH_PTR(keep
, tmp_keep
) {
123 ret
= merge_sm_states(ret
, tmp_keep
);
124 } END_FOR_EACH_PTR(tmp_keep
);
125 merge_pools(&ret
->my_pools
, sm
->my_pools
);
126 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
129 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
134 static struct state_list
*filter_stack(struct state_list
*pre_list
,
135 struct state_list_stack
*stack
)
137 struct state_list
*ret
= NULL
;
138 struct sm_state
*tmp
;
139 struct sm_state
*filtered_state
;
145 FOR_EACH_PTR(pre_list
, tmp
) {
146 filtered_state
= remove_my_pools(tmp
, stack
, &modified
);
147 if (filtered_state
&& modified
)
148 add_ptr_list(&ret
, filtered_state
);
149 } END_FOR_EACH_PTR(tmp
);
153 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
155 struct sm_state
*tmp
;
157 FOR_EACH_PTR(checked
, tmp
) {
160 } END_FOR_EACH_PTR(tmp
);
164 static void separate_pools(struct sm_state
*sm_state
, int comparison
, int num
,
166 struct state_list_stack
**true_stack
,
167 struct state_list_stack
**false_stack
,
168 struct state_list
**checked
)
170 struct state_list
*list
;
173 int free_checked
= 0;
174 struct state_list
*checked_states
= NULL
;
177 if (checked
== NULL
) {
179 checked
= &checked_states
;
182 if (is_checked(*checked
, sm_state
)) {
185 add_ptr_list(checked
, sm_state
);
187 if (stopper
++ >= 500) {
188 smatch_msg("internal error: too much recursion going on here");
192 FOR_EACH_PTR(sm_state
->my_pools
, list
) {
193 s
= get_sm_state_slist(list
, sm_state
->name
, sm_state
->owner
,
195 istrue
= !possibly_false(comparison
,
196 (struct data_info
*)s
->state
->data
, num
,
198 isfalse
= !possibly_true(comparison
,
199 (struct data_info
*)s
->state
->data
,
202 if (debug_implied_states
|| debug_states
) {
203 if (istrue
&& isfalse
) {
204 printf("'%s = %s' from %d does not exist. %p\n",
205 s
->name
, show_state(s
->state
),
208 printf("'%s = %s' from %d is true. %p\n",
209 s
->name
, show_state(s
->state
),
211 } else if (isfalse
) {
212 printf("'%s = %s' from %d is false. %p\n",
213 s
->name
, show_state(s
->state
),
216 printf("'%s = %s' from %d could be true or "
217 "false. %p\n", s
->name
,
218 show_state(s
->state
), s
->line
, list
);
222 add_pool(true_stack
, list
);
225 add_pool(false_stack
, list
);
227 } END_FOR_EACH_PTR(list
);
228 FOR_EACH_PTR(sm_state
->pre_merge
, s
) {
229 separate_pools(s
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
230 } END_FOR_EACH_PTR(s
);
235 static void get_eq_neq(struct sm_state
*sm_state
, int comparison
, int num
,
237 struct state_list
*pre_list
,
238 struct state_list
**true_states
,
239 struct state_list
**false_states
)
241 struct state_list_stack
*true_stack
= NULL
;
242 struct state_list_stack
*false_stack
= NULL
;
244 if (debug_implied_states
|| debug_states
) {
246 smatch_msg("checking implications: (%s %s %d)",
247 sm_state
->name
, show_special(comparison
), num
);
249 smatch_msg("checking implications: (%d %s %s)",
250 num
, show_special(comparison
), sm_state
->name
);
253 separate_pools(sm_state
, comparison
, num
, left
, &true_stack
, &false_stack
, NULL
);
255 DIMPLIED("filtering true stack.\n");
256 *true_states
= filter_stack(pre_list
, false_stack
);
257 DIMPLIED("filtering false stack.\n");
258 *false_states
= filter_stack(pre_list
, true_stack
);
259 free_stack(&true_stack
);
260 free_stack(&false_stack
);
261 if (debug_implied_states
|| debug_states
) {
262 printf("These are the implied states for the true path:\n");
263 __print_slist(*true_states
);
264 printf("These are the implied states for the false path:\n");
265 __print_slist(*false_states
);
269 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
271 expr
= strip_expr(expr
);
272 if (expr
->type
== EXPR_ASSIGNMENT
)
273 return get_implication_variable(expr
->left
, symp
);
274 return get_variable_from_expr(expr
, symp
);
277 static void handle_comparison(struct expression
*expr
,
278 struct state_list
**implied_true
,
279 struct state_list
**implied_false
)
283 struct sm_state
*state
;
287 value
= get_value(expr
->left
);
288 if (value
== UNDEFINED
) {
289 value
= get_value(expr
->right
);
290 if (value
== UNDEFINED
)
295 name
= get_implication_variable(expr
->left
, &sym
);
297 name
= get_implication_variable(expr
->right
, &sym
);
300 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
303 if (!is_merged(state
)) {
304 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), state
->name
);
307 get_eq_neq(state
, expr
->op
, value
, left
, __get_cur_slist(), implied_true
, implied_false
);
308 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
309 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
314 static void get_tf_states(struct expression
*expr
,
315 struct state_list
**implied_true
,
316 struct state_list
**implied_false
)
320 struct sm_state
*state
;
322 if (expr
->type
== EXPR_COMPARE
) {
323 handle_comparison(expr
, implied_true
, implied_false
);
326 if (expr
->type
== EXPR_ASSIGNMENT
) {
327 /* most of the time ->my_pools will be empty here because we
328 just set the state, but if have assigned a conditional
329 function there are implications. */
333 name
= get_variable_from_expr(expr
, &sym
);
336 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
339 if (!is_merged(state
)) {
340 DIMPLIED("%d '%s' has no pools.\n", get_lineno(), state
->name
);
343 get_eq_neq(state
, SPECIAL_NOTEQUAL
, 0, 1, __get_cur_slist(), implied_true
, implied_false
);
344 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
345 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
350 static void implied_states_hook(struct expression
*expr
)
352 struct sm_state
*state
;
353 struct sm_state
*clone
;
354 struct state_list
*implied_true
= NULL
;
355 struct state_list
*implied_false
= NULL
;
357 if (option_no_implied
)
360 get_tf_states(expr
, &implied_true
, &implied_false
);
362 FOR_EACH_PTR(implied_true
, state
) {
363 clone
= clone_state(state
);
364 __set_true_false_sm(clone
, NULL
);
365 } END_FOR_EACH_PTR(state
);
366 free_slist(&implied_true
);
368 FOR_EACH_PTR(implied_false
, state
) {
369 clone
= clone_state(state
);
370 __set_true_false_sm(NULL
, clone
);
371 } END_FOR_EACH_PTR(state
);
372 free_slist(&implied_false
);
375 void get_implications(char *name
, struct symbol
*sym
, int comparison
, int num
,
376 struct state_list
**true_states
,
377 struct state_list
**false_states
)
381 sm
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
384 if (slist_has_state(sm
->possible
, &undefined
))
386 get_eq_neq(sm
, comparison
, num
, 1, __get_cur_slist(), true_states
, false_states
);
389 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
390 struct expression
*case_expr
,
391 struct state_list
**raw_slist
)
396 struct sm_state
*true_sm
;
397 struct sm_state
*false_sm
;
398 struct state_list
*true_states
= NULL
;
399 struct state_list
*false_states
= NULL
;
400 struct state_list
*true_clone
;
401 struct state_list
*false_clone
;
402 struct state_list
*ret
= clone_slist(*raw_slist
);
407 name
= get_variable_from_expr(switch_expr
, &sym
);
410 sm
= get_sm_state_slist(*raw_slist
, name
, SMATCH_EXTRA
, sym
);
411 val
= get_value(case_expr
);
412 if (val
== UNDEFINED
)
415 get_eq_neq(sm
, SPECIAL_EQUAL
, val
, 1, *raw_slist
, &true_states
, &false_states
);
418 true_sm
= get_sm_state_slist(true_states
, name
, SMATCH_EXTRA
, sym
);
420 set_state_slist(&true_states
, name
, SMATCH_EXTRA
, sym
, alloc_extra_state(val
));
421 false_sm
= get_sm_state_slist(false_states
, name
, SMATCH_EXTRA
, sym
);
423 set_state_slist(&false_states
, name
, SMATCH_EXTRA
, sym
, add_filter(sm
?sm
->state
:NULL
, val
));
424 true_clone
= clone_slist_and_states(true_states
);
425 false_clone
= clone_slist_and_states(false_states
);
426 overwrite_slist(false_clone
, raw_slist
);
427 overwrite_slist(true_clone
, &ret
);
428 free_slist(&true_clone
);
429 free_slist(&false_clone
);
430 free_slist(&true_states
);
431 free_slist(&false_states
);
437 void __extra_match_condition(struct expression
*expr
);
438 void register_implications(int id
)
440 add_hook(&implied_states_hook
, CONDITION_HOOK
);
441 add_hook(&__extra_match_condition
, CONDITION_HOOK
);