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 pool_in_pools(struct state_list
*pool
,
60 struct state_list_stack
*pools
)
62 struct state_list
*tmp
;
64 FOR_EACH_PTR(pools
, tmp
) {
69 } END_FOR_EACH_PTR(tmp
);
73 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
74 struct state_list_stack
*pools
, int *modified
)
76 struct sm_state
*ret
= NULL
;
77 struct sm_state
*left
;
78 struct sm_state
*right
;
84 if (pool_in_pools(sm
->my_pool
, pools
)) {
85 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
86 show_state(sm
->state
), sm
->line
);
92 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
97 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
98 left
= remove_my_pools(sm
->pre_left
, pools
, &removed
);
99 right
= remove_my_pools(sm
->pre_right
, pools
, &removed
);
101 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
105 if (!left
&& !right
) {
106 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
111 ret
= clone_state(right
);
113 ret
->pre_right
= right
;
114 ret
->pre_left
= NULL
;
115 ret
->my_pool
= sm
->my_pool
;
117 ret
= clone_state(left
);
119 ret
->pre_left
= left
;
120 ret
->pre_right
= NULL
;
121 ret
->my_pool
= sm
->my_pool
;
123 ret
= merge_sm_states(left
, right
);
124 ret
->my_pool
= sm
->my_pool
;
126 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
130 static struct state_list
*filter_stack(struct state_list
*pre_list
,
131 struct state_list_stack
*stack
)
133 struct state_list
*ret
= NULL
;
134 struct sm_state
*tmp
;
135 struct sm_state
*filtered_state
;
141 FOR_EACH_PTR(pre_list
, tmp
) {
145 filtered_state
= remove_my_pools(tmp
, stack
, &modified
);
146 if (filtered_state
&& modified
)
147 add_ptr_list(&ret
, filtered_state
);
148 } END_FOR_EACH_PTR(tmp
);
152 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
154 struct sm_state
*tmp
;
156 FOR_EACH_PTR(checked
, tmp
) {
159 } END_FOR_EACH_PTR(tmp
);
163 static void separate_pools(struct sm_state
*sm_state
, int comparison
, int num
,
165 struct state_list_stack
**true_stack
,
166 struct state_list_stack
**false_stack
,
167 struct state_list
**checked
)
171 int free_checked
= 0;
172 struct state_list
*checked_states
= NULL
;
178 if (checked
== NULL
) {
180 checked
= &checked_states
;
183 if (is_checked(*checked
, sm_state
)) {
186 add_ptr_list(checked
, sm_state
);
188 if (stopper
++ >= 500) {
189 smatch_msg("internal error: too much recursion going on here");
193 if (sm_state
->my_pool
) {
194 s
= get_sm_state_slist(sm_state
->my_pool
, sm_state
->name
, sm_state
->owner
,
197 istrue
= !possibly_false(comparison
,
198 (struct data_info
*)s
->state
->data
, num
,
200 isfalse
= !possibly_true(comparison
,
201 (struct data_info
*)s
->state
->data
,
204 if (debug_implied_states
|| debug_states
) {
205 if (istrue
&& isfalse
) {
206 printf("'%s = %s' from %d does not exist.\n",
207 s
->name
, show_state(s
->state
),
210 printf("'%s = %s' from %d is true.\n",
211 s
->name
, show_state(s
->state
),
213 } else if (isfalse
) {
214 printf("'%s = %s' from %d is false.\n",
215 s
->name
, show_state(s
->state
),
218 printf("'%s = %s' from %d could be true or "
220 show_state(s
->state
), s
->line
);
224 add_pool(true_stack
, s
->my_pool
);
227 add_pool(false_stack
, s
->my_pool
);
230 separate_pools(sm_state
->pre_left
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
231 separate_pools(sm_state
->pre_right
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
236 static void get_eq_neq(struct sm_state
*sm_state
, int comparison
, int num
,
238 struct state_list
*pre_list
,
239 struct state_list
**true_states
,
240 struct state_list
**false_states
)
242 struct state_list_stack
*true_stack
= NULL
;
243 struct state_list_stack
*false_stack
= NULL
;
245 if (debug_implied_states
|| debug_states
) {
247 smatch_msg("checking implications: (%s %s %d)",
248 sm_state
->name
, show_special(comparison
), num
);
250 smatch_msg("checking implications: (%d %s %s)",
251 num
, show_special(comparison
), sm_state
->name
);
254 separate_pools(sm_state
, comparison
, num
, left
, &true_stack
, &false_stack
, NULL
);
256 DIMPLIED("filtering true stack.\n");
257 *true_states
= filter_stack(pre_list
, false_stack
);
258 DIMPLIED("filtering false stack.\n");
259 *false_states
= filter_stack(pre_list
, true_stack
);
260 free_stack(&true_stack
);
261 free_stack(&false_stack
);
262 if (debug_implied_states
|| debug_states
) {
263 printf("These are the implied states for the true path:\n");
264 __print_slist(*true_states
);
265 printf("These are the implied states for the false path:\n");
266 __print_slist(*false_states
);
270 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
272 expr
= strip_expr(expr
);
273 if (expr
->type
== EXPR_ASSIGNMENT
)
274 return get_implication_variable(expr
->left
, symp
);
275 return get_variable_from_expr(expr
, symp
);
278 static void handle_comparison(struct expression
*expr
,
279 struct state_list
**implied_true
,
280 struct state_list
**implied_false
)
284 struct sm_state
*state
;
288 value
= get_value(expr
->left
);
289 if (value
== UNDEFINED
) {
290 value
= get_value(expr
->right
);
291 if (value
== UNDEFINED
)
296 name
= get_implication_variable(expr
->left
, &sym
);
298 name
= get_implication_variable(expr
->right
, &sym
);
301 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
304 if (!is_merged(state
)) {
305 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), state
->name
);
308 get_eq_neq(state
, expr
->op
, value
, left
, __get_cur_slist(), implied_true
, implied_false
);
309 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
310 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
315 static void get_tf_states(struct expression
*expr
,
316 struct state_list
**implied_true
,
317 struct state_list
**implied_false
)
321 struct sm_state
*state
;
323 if (expr
->type
== EXPR_COMPARE
) {
324 handle_comparison(expr
, implied_true
, implied_false
);
327 if (expr
->type
== EXPR_ASSIGNMENT
) {
328 /* most of the time ->my_pools will be empty here because we
329 just set the state, but if have assigned a conditional
330 function there are implications. */
334 name
= get_variable_from_expr(expr
, &sym
);
337 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
340 if (!is_merged(state
)) {
341 DIMPLIED("%d '%s' has no pools.\n", get_lineno(), state
->name
);
344 get_eq_neq(state
, SPECIAL_NOTEQUAL
, 0, 1, __get_cur_slist(), implied_true
, implied_false
);
345 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
346 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
351 static void implied_states_hook(struct expression
*expr
)
353 struct sm_state
*state
;
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 __set_true_false_sm(state
, NULL
);
364 } END_FOR_EACH_PTR(state
);
365 free_slist(&implied_true
);
367 FOR_EACH_PTR(implied_false
, state
) {
368 __set_true_false_sm(NULL
, state
);
369 } END_FOR_EACH_PTR(state
);
370 free_slist(&implied_false
);
373 void get_implications(char *name
, struct symbol
*sym
, int comparison
, int num
,
374 struct state_list
**true_states
,
375 struct state_list
**false_states
)
379 sm
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
382 if (slist_has_state(sm
->possible
, &undefined
))
384 get_eq_neq(sm
, comparison
, num
, 1, __get_cur_slist(), true_states
, false_states
);
387 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
388 struct expression
*case_expr
,
389 struct state_list
**raw_slist
)
394 struct sm_state
*true_sm
;
395 struct sm_state
*false_sm
;
396 struct state_list
*true_states
= NULL
;
397 struct state_list
*false_states
= NULL
;
398 struct state_list
*ret
= clone_slist(*raw_slist
);
403 name
= get_variable_from_expr(switch_expr
, &sym
);
406 sm
= get_sm_state_slist(*raw_slist
, name
, SMATCH_EXTRA
, sym
);
407 val
= get_value(case_expr
);
408 if (val
== UNDEFINED
)
411 get_eq_neq(sm
, SPECIAL_EQUAL
, val
, 1, *raw_slist
, &true_states
, &false_states
);
414 true_sm
= get_sm_state_slist(true_states
, name
, SMATCH_EXTRA
, sym
);
416 set_state_slist(&true_states
, name
, SMATCH_EXTRA
, sym
, alloc_extra_state(val
));
417 false_sm
= get_sm_state_slist(false_states
, name
, SMATCH_EXTRA
, sym
);
419 set_state_slist(&false_states
, name
, SMATCH_EXTRA
, sym
, add_filter(sm
?sm
->state
:NULL
, val
));
420 overwrite_slist(false_states
, raw_slist
);
421 overwrite_slist(true_states
, &ret
);
422 free_slist(&true_states
);
423 free_slist(&false_states
);
429 void __extra_match_condition(struct expression
*expr
);
430 void register_implications(int id
)
432 add_hook(&implied_states_hook
, CONDITION_HOOK
);
433 add_hook(&__extra_match_condition
, CONDITION_HOOK
);