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_pool
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_pool. An sm_state only has one ->my_pool and
43 * that is the pool where it was first set. Implied states sometimes have a
44 * my_pool to reflect that the code flowed through that path.
45 * merge_sm_state() sets ->left and ->right. (These are the states which were
46 * merged to form the current state.)
47 * If an sm_state is not the same on both sides of a merge, it
48 * gets a ->my_pool set for both sides. The result is a merged
49 * state that has it's ->left and ->right pointers set. Merged states
50 * do not immediately have any my_pool set, but maybe will later
51 * when they themselves are merged.
52 * A pool is a list of all the states that were set at the time.
56 #include "smatch_slist.h"
57 #include "smatch_extra.h"
59 #define DIMPLIED(msg...) do { if (debug_implied_states) printf(msg); } while (0)
61 int debug_implied_states
= 0;
62 int option_no_implied
= 0;
64 static int print_once
= 0;
66 static struct range_list
*my_list
= NULL
;
67 static struct data_range
*my_range
;
69 static struct range_list
*tmp_range_list(long num
)
71 __free_ptr_list((struct ptr_list
**)&my_list
);
72 my_range
= alloc_range(num
, num
);
75 add_ptr_list(&my_list
, my_range
);
79 static int pool_in_pools(struct state_list
*pool
,
80 struct state_list_stack
*pools
)
82 struct state_list
*tmp
;
84 FOR_EACH_PTR(pools
, tmp
) {
89 } END_FOR_EACH_PTR(tmp
);
93 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
94 struct state_list_stack
*pools
, int *modified
)
96 struct sm_state
*ret
= NULL
;
97 struct sm_state
*left
;
98 struct sm_state
*right
;
104 if (sm
->nr_children
> 5000) {
106 sm_msg("debug: remove_my_pools %s nr_children %d",
107 sm
->name
, sm
->nr_children
);
112 if (pool_in_pools(sm
->my_pool
, pools
)) {
113 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
114 show_state(sm
->state
), sm
->line
);
119 if (!is_merged(sm
)) {
120 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
125 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
126 left
= remove_my_pools(sm
->left
, pools
, &removed
);
127 right
= remove_my_pools(sm
->right
, pools
, &removed
);
129 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
133 if (!left
&& !right
) {
134 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
139 ret
= clone_state(right
);
143 ret
->my_pool
= sm
->my_pool
;
145 ret
= clone_state(left
);
149 ret
->my_pool
= sm
->my_pool
;
151 ret
= merge_sm_states(left
, right
);
152 ret
->my_pool
= sm
->my_pool
;
155 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
159 static struct state_list
*filter_stack(struct state_list
*pre_list
,
160 struct state_list_stack
*stack
)
162 struct state_list
*ret
= NULL
;
163 struct sm_state
*tmp
;
164 struct sm_state
*filtered_state
;
171 FOR_EACH_PTR(pre_list
, tmp
) {
173 filtered_state
= remove_my_pools(tmp
, stack
, &modified
);
174 if (filtered_state
&& modified
) {
175 add_ptr_list(&ret
, filtered_state
);
176 if ((counter
++)%10 && out_of_memory())
180 } END_FOR_EACH_PTR(tmp
);
184 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
186 struct sm_state
*tmp
;
188 FOR_EACH_PTR(checked
, tmp
) {
191 } END_FOR_EACH_PTR(tmp
);
195 static void separate_pools(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
197 struct state_list_stack
**true_stack
,
198 struct state_list_stack
**false_stack
,
199 struct state_list
**checked
)
203 int free_checked
= 0;
204 struct state_list
*checked_states
= NULL
;
210 Sometimes the implications are just too big to deal with
211 so we bail. Theoretically, implications only get rid of
212 false positives and don't affect actual bugs.
214 if (sm_state
->nr_children
> 5000) {
216 sm_msg("debug: seperate_pools %s nr_children %d",
217 sm_state
->name
, sm_state
->nr_children
);
222 if (checked
== NULL
) {
223 checked
= &checked_states
;
226 if (is_checked(*checked
, sm_state
)) {
229 add_ptr_list(checked
, sm_state
);
231 if (sm_state
->my_pool
) {
232 if (is_implied(sm_state
)) {
233 s
= get_sm_state_slist(sm_state
->my_pool
,
234 sm_state
->owner
, sm_state
->name
,
240 istrue
= !possibly_false_range_list(comparison
,
241 (struct data_info
*)s
->state
->data
,
243 isfalse
= !possibly_true_range_list(comparison
,
244 (struct data_info
*)s
->state
->data
,
247 if (debug_implied_states
|| debug_states
) {
248 if (istrue
&& isfalse
) {
249 printf("'%s = %s' from %d does not exist.\n",
250 s
->name
, show_state(s
->state
),
253 printf("'%s = %s' from %d is true.\n",
254 s
->name
, show_state(s
->state
),
256 } else if (isfalse
) {
257 printf("'%s = %s' from %d is false.\n",
258 s
->name
, show_state(s
->state
),
261 printf("'%s = %s' from %d could be true or "
263 show_state(s
->state
), s
->line
);
267 add_pool(true_stack
, s
->my_pool
);
270 add_pool(false_stack
, s
->my_pool
);
273 separate_pools(sm_state
->left
, comparison
, vals
, left
, true_stack
, false_stack
, checked
);
274 separate_pools(sm_state
->right
, comparison
, vals
, left
, true_stack
, false_stack
, checked
);
279 static void get_eq_neq(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
281 struct state_list
*pre_list
,
282 struct state_list
**true_states
,
283 struct state_list
**false_states
)
285 struct state_list_stack
*true_stack
= NULL
;
286 struct state_list_stack
*false_stack
= NULL
;
288 if (debug_implied_states
|| debug_states
) {
290 sm_msg("checking implications: (%s %s %s)",
291 sm_state
->name
, show_special(comparison
), show_ranges(vals
));
293 sm_msg("checking implications: (%s %s %s)",
294 show_ranges(vals
), show_special(comparison
), sm_state
->name
);
297 separate_pools(sm_state
, comparison
, vals
, left
, &true_stack
, &false_stack
, NULL
);
299 DIMPLIED("filtering true stack.\n");
300 *true_states
= filter_stack(pre_list
, false_stack
);
301 DIMPLIED("filtering false stack.\n");
302 *false_states
= filter_stack(pre_list
, true_stack
);
303 free_stack(&true_stack
);
304 free_stack(&false_stack
);
305 if (debug_implied_states
|| debug_states
) {
306 printf("These are the implied states for the true path:\n");
307 __print_slist(*true_states
);
308 printf("These are the implied states for the false path:\n");
309 __print_slist(*false_states
);
313 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
315 expr
= strip_expr(expr
);
316 if (expr
->type
== EXPR_ASSIGNMENT
)
317 return get_implication_variable(expr
->left
, symp
);
318 return get_variable_from_expr(expr
, symp
);
321 static void handle_comparison(struct expression
*expr
,
322 struct state_list
**implied_true
,
323 struct state_list
**implied_false
)
327 struct sm_state
*state
;
331 value
= get_value(expr
->left
);
332 if (value
== UNDEFINED
) {
333 value
= get_value(expr
->right
);
334 if (value
== UNDEFINED
)
339 name
= get_implication_variable(expr
->left
, &sym
);
341 name
= get_implication_variable(expr
->right
, &sym
);
344 state
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
347 if (!is_merged(state
)) {
348 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), state
->name
);
351 get_eq_neq(state
, expr
->op
, tmp_range_list(value
), left
, __get_cur_slist(), implied_true
, implied_false
);
352 delete_state_slist(implied_true
, SMATCH_EXTRA
, name
, sym
);
353 delete_state_slist(implied_false
, SMATCH_EXTRA
, name
, sym
);
358 static void get_tf_states(struct expression
*expr
,
359 struct state_list
**implied_true
,
360 struct state_list
**implied_false
)
364 struct sm_state
*state
;
366 if (expr
->type
== EXPR_COMPARE
) {
367 handle_comparison(expr
, implied_true
, implied_false
);
370 if (expr
->type
== EXPR_ASSIGNMENT
) {
371 /* most of the time ->my_pools will be empty here because we
372 just set the state, but if have assigned a conditional
373 function there are implications. */
377 name
= get_variable_from_expr(expr
, &sym
);
380 state
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
383 if (!is_merged(state
)) {
384 DIMPLIED("%d '%s' has no pools.\n", get_lineno(), state
->name
);
387 get_eq_neq(state
, SPECIAL_NOTEQUAL
, tmp_range_list(0), 1, __get_cur_slist(), implied_true
, implied_false
);
388 delete_state_slist(implied_true
, SMATCH_EXTRA
, name
, sym
);
389 delete_state_slist(implied_false
, SMATCH_EXTRA
, name
, sym
);
394 static void implied_states_hook(struct expression
*expr
)
396 struct sm_state
*state
;
397 struct state_list
*implied_true
= NULL
;
398 struct state_list
*implied_false
= NULL
;
400 if (option_no_implied
)
403 get_tf_states(expr
, &implied_true
, &implied_false
);
405 FOR_EACH_PTR(implied_true
, state
) {
406 __set_true_false_sm(state
, NULL
);
407 } END_FOR_EACH_PTR(state
);
408 free_slist(&implied_true
);
410 FOR_EACH_PTR(implied_false
, state
) {
411 __set_true_false_sm(NULL
, state
);
412 } END_FOR_EACH_PTR(state
);
413 free_slist(&implied_false
);
416 struct range_list
*__get_implied_values(struct expression
*switch_expr
)
420 struct smatch_state
*state
;
421 struct range_list
*ret
= NULL
;
423 name
= get_variable_from_expr(switch_expr
, &sym
);
426 state
= get_state(SMATCH_EXTRA
, name
, sym
);
429 ret
= clone_range_list(((struct data_info
*)state
->data
)->value_ranges
);
433 add_range(&ret
, whole_range
.min
, whole_range
.max
);
437 void get_implications(char *name
, struct symbol
*sym
, int comparison
, int num
,
438 struct state_list
**true_states
,
439 struct state_list
**false_states
)
443 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
446 if (slist_has_state(sm
->possible
, &undefined
))
448 get_eq_neq(sm
, comparison
, tmp_range_list(num
), 1, __get_cur_slist(), true_states
, false_states
);
451 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
452 struct expression
*case_expr
,
453 struct range_list_stack
**remaining_cases
,
454 struct state_list
**raw_slist
)
459 struct sm_state
*true_sm
;
460 struct state_list
*true_states
= NULL
;
461 struct state_list
*false_states
= NULL
;
462 struct state_list
*ret
= clone_slist(*raw_slist
);
464 struct data_range
*range
;
465 struct range_list
*vals
= NULL
;
467 name
= get_variable_from_expr(switch_expr
, &sym
);
470 sm
= get_sm_state_slist(*raw_slist
, SMATCH_EXTRA
, name
, sym
);
472 vals
= top_range_list(*remaining_cases
);
474 val
= get_value(case_expr
);
475 if (val
== UNDEFINED
) {
478 filter_top_range_list(remaining_cases
, val
);
479 range
= alloc_range(val
, val
);
480 add_ptr_list(&vals
, range
);
484 get_eq_neq(sm
, SPECIAL_EQUAL
, vals
, 1, *raw_slist
, &true_states
, &false_states
);
487 true_sm
= get_sm_state_slist(true_states
, SMATCH_EXTRA
, name
, sym
);
489 set_state_slist(&true_states
, SMATCH_EXTRA
, name
, sym
, alloc_extra_state_range_list(vals
));
490 overwrite_slist(true_states
, &ret
);
491 free_slist(&true_states
);
492 free_slist(&false_states
);
498 static void match_end_func(struct symbol
*sym
)
503 void __extra_match_condition(struct expression
*expr
);
504 void register_implications(int id
)
506 add_hook(&implied_states_hook
, CONDITION_HOOK
);
507 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
508 add_hook(&match_end_func
, END_FUNC_HOOK
);