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. The my pool gets set when
44 * code paths merge. States that have been set since the last merge do
45 * not have a ->my_pool.
46 * merge_sm_state() sets ->left and ->right. (These are the states which were
47 * merged to form the current state.)
48 * a pool: a pool is an slist that has been merged with another slist.
54 #include "smatch_slist.h"
55 #include "smatch_extra.h"
57 char *implied_debug_msg
;
58 #define DIMPLIED(msg...) do { if (option_debug_implied) printf(msg); } while (0)
60 int option_debug_implied
= 0;
61 int option_no_implied
= 0;
68 * It messes things up to free range list allocations. This helper fuction
69 * lets us reuse memory instead of doing new allocations.
71 static struct range_list
*tmp_range_list(long long num
)
73 static struct range_list
*my_list
= NULL
;
74 static struct data_range
*my_range
;
76 __free_ptr_list((struct ptr_list
**)&my_list
);
77 my_range
= alloc_range(num
, num
);
80 add_ptr_list(&my_list
, my_range
);
85 * If 'foo' == 99 add it that pool to the true pools. If it's false, add it to
86 * the false pools. If we're not sure, then we don't add it to either.
88 static void do_compare(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
90 struct state_list_stack
**true_stack
,
91 struct state_list_stack
**false_stack
)
97 if (!sm_state
->my_pool
)
100 if (is_implied(sm_state
)) {
101 s
= get_sm_state_slist(sm_state
->my_pool
,
102 sm_state
->owner
, sm_state
->name
,
109 if (option_debug_implied
|| option_debug
)
110 sm_msg("%s from %d, has borrowed implications.",
111 sm_state
->name
, sm_state
->line
);
115 istrue
= !possibly_false_range_list_lr(comparison
, get_dinfo(s
->state
), vals
, lr
);
116 isfalse
= !possibly_true_range_list_lr(comparison
, get_dinfo(s
->state
), vals
, lr
);
118 if (option_debug_implied
|| option_debug
) {
119 if (istrue
&& isfalse
) {
120 printf("'%s = %s' from %d does not exist.\n", s
->name
,
121 show_state(s
->state
), s
->line
);
123 printf("'%s = %s' from %d is true.\n", s
->name
, show_state(s
->state
),
125 } else if (isfalse
) {
126 printf("'%s = %s' from %d is false.\n", s
->name
, show_state(s
->state
),
129 printf("'%s = %s' from %d could be true or false.\n", s
->name
,
130 show_state(s
->state
), s
->line
);
134 add_pool(true_stack
, s
->my_pool
);
137 add_pool(false_stack
, s
->my_pool
);
140 static int pool_in_pools(struct state_list
*pool
,
141 struct state_list_stack
*pools
)
143 struct state_list
*tmp
;
145 FOR_EACH_PTR(pools
, tmp
) {
150 } END_FOR_EACH_PTR(tmp
);
154 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
156 struct sm_state
*tmp
;
158 FOR_EACH_PTR(checked
, tmp
) {
161 } END_FOR_EACH_PTR(tmp
);
167 * Example code: if (foo == 99) {
169 * Say 'foo' is a merged state that has many possible values. It is the combination
170 * of merges. separate_pools() iterates through the pools recursively and calls
171 * do_compare() for each time 'foo' was set.
173 static void separate_pools(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
175 struct state_list_stack
**true_stack
,
176 struct state_list_stack
**false_stack
,
177 struct state_list
**checked
)
179 int free_checked
= 0;
180 struct state_list
*checked_states
= NULL
;
186 Sometimes the implications are just too big to deal with
187 so we bail. Theoretically, bailing out here can cause more false
188 positives but won't hide actual bugs.
190 if (sm_state
->nr_children
> 4000) {
192 (char *) "debug: seperate_pools: nr_children over 4000.";
196 if (checked
== NULL
) {
197 checked
= &checked_states
;
200 if (is_checked(*checked
, sm_state
))
202 add_ptr_list(checked
, sm_state
);
204 do_compare(sm_state
, comparison
, vals
, lr
, true_stack
, false_stack
);
206 separate_pools(sm_state
->left
, comparison
, vals
, lr
, true_stack
, false_stack
, checked
);
207 separate_pools(sm_state
->right
, comparison
, vals
, lr
, true_stack
, false_stack
, checked
);
212 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
213 struct state_list_stack
*pools
, int *modified
)
215 struct sm_state
*ret
= NULL
;
216 struct sm_state
*left
;
217 struct sm_state
*right
;
223 if (sm
->nr_children
> 4000) {
225 (char *) "debug: remove_my_pools: nr_children over 4000";
229 if (pool_in_pools(sm
->my_pool
, pools
)) {
230 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
231 show_state(sm
->state
), sm
->line
);
236 if (!is_merged(sm
)) {
237 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
242 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
243 left
= remove_my_pools(sm
->left
, pools
, &removed
);
244 right
= remove_my_pools(sm
->right
, pools
, &removed
);
246 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
250 if (!left
&& !right
) {
251 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
256 ret
= clone_sm(right
);
260 ret
->my_pool
= sm
->my_pool
;
262 ret
= clone_sm(left
);
266 ret
->my_pool
= sm
->my_pool
;
268 ret
= merge_sm_states(left
, right
);
269 ret
->my_pool
= sm
->my_pool
;
272 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
276 static struct state_list
*filter_stack(struct state_list
*pre_list
,
277 struct state_list_stack
*stack
)
279 struct state_list
*ret
= NULL
;
280 struct sm_state
*tmp
;
281 struct sm_state
*filtered_sm
;
287 FOR_EACH_PTR(pre_list
, tmp
) {
289 filtered_sm
= remove_my_pools(tmp
, stack
, &modified
);
290 if (filtered_sm
&& modified
) {
291 filtered_sm
->name
= tmp
->name
;
292 filtered_sm
->sym
= tmp
->sym
;
293 add_ptr_list(&ret
, filtered_sm
);
298 } END_FOR_EACH_PTR(tmp
);
302 static void separate_and_filter(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
304 struct state_list
*pre_list
,
305 struct state_list
**true_states
,
306 struct state_list
**false_states
)
308 struct state_list_stack
*true_stack
= NULL
;
309 struct state_list_stack
*false_stack
= NULL
;
310 struct timeval time_before
;
311 struct timeval time_after
;
313 gettimeofday(&time_before
, NULL
);
315 if (!is_merged(sm_state
)) {
316 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), sm_state
->name
);
320 if (option_debug_implied
|| option_debug
) {
322 sm_msg("checking implications: (%s %s %s)",
323 sm_state
->name
, show_special(comparison
), show_ranges(vals
));
325 sm_msg("checking implications: (%s %s %s)",
326 show_ranges(vals
), show_special(comparison
), sm_state
->name
);
329 separate_pools(sm_state
, comparison
, vals
, lr
, &true_stack
, &false_stack
, NULL
);
331 DIMPLIED("filtering true stack.\n");
332 *true_states
= filter_stack(pre_list
, false_stack
);
333 DIMPLIED("filtering false stack.\n");
334 *false_states
= filter_stack(pre_list
, true_stack
);
335 free_stack(&true_stack
);
336 free_stack(&false_stack
);
337 if (option_debug_implied
|| option_debug
) {
338 printf("These are the implied states for the true path:\n");
339 __print_slist(*true_states
);
340 printf("These are the implied states for the false path:\n");
341 __print_slist(*false_states
);
344 gettimeofday(&time_after
, NULL
);
345 if (time_after
.tv_sec
- time_before
.tv_sec
> 7)
346 __bail_on_rest_of_function
= 1;
349 static struct expression
*get_left_most_expr(struct expression
*expr
)
351 expr
= strip_expr(expr
);
352 if (expr
->type
== EXPR_ASSIGNMENT
)
353 return get_left_most_expr(expr
->left
);
357 static int is_merged_expr(struct expression
*expr
)
362 if (get_value(expr
, &dummy
))
364 sm
= get_sm_state_expr(SMATCH_EXTRA
, expr
);
372 static void delete_equiv_slist(struct state_list
**slist
, const char *name
, struct symbol
*sym
)
374 struct smatch_state
*state
;
375 struct data_info
*dinfo
;
376 struct relation
*rel
;
378 state
= get_state(SMATCH_EXTRA
, name
, sym
);
379 dinfo
= get_dinfo(state
);
380 if (!dinfo
->related
) {
381 delete_state_slist(slist
, SMATCH_EXTRA
, name
, sym
);
385 FOR_EACH_PTR(dinfo
->related
, rel
) {
386 delete_state_slist(slist
, SMATCH_EXTRA
, rel
->name
, rel
->sym
);
387 } END_FOR_EACH_PTR(rel
);
390 static void handle_comparison(struct expression
*expr
,
391 struct state_list
**implied_true
,
392 struct state_list
**implied_false
)
394 struct sm_state
*sm
= NULL
;
395 struct range_list
*ranges
= NULL
;
396 struct expression
*left
;
397 struct expression
*right
;
400 left
= get_left_most_expr(expr
->left
);
401 right
= get_left_most_expr(expr
->right
);
403 if (is_merged_expr(left
)) {
405 sm
= get_sm_state_expr(SMATCH_EXTRA
, left
);
406 ranges
= get_range_list(right
);
407 } else if (is_merged_expr(right
)) {
409 sm
= get_sm_state_expr(SMATCH_EXTRA
, right
);
410 ranges
= get_range_list(left
);
413 if (!ranges
|| !sm
) {
414 free_range_list(&ranges
);
418 separate_and_filter(sm
, expr
->op
, ranges
, lr
, __get_cur_slist(), implied_true
, implied_false
);
419 free_range_list(&ranges
);
420 delete_equiv_slist(implied_true
, sm
->name
, sm
->sym
);
421 delete_equiv_slist(implied_false
, sm
->name
, sm
->sym
);
424 static void handle_zero_comparison(struct expression
*expr
,
425 struct state_list
**implied_true
,
426 struct state_list
**implied_false
)
432 if (expr
->type
== EXPR_POSTOP
)
433 expr
= strip_expr(expr
->unop
);
435 if (expr
->type
== EXPR_ASSIGNMENT
) {
436 /* most of the time ->my_pools will be empty here because we
437 just set the state, but if have assigned a conditional
438 function there are implications. */
442 name
= get_variable_from_expr(expr
, &sym
);
445 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
449 separate_and_filter(sm
, SPECIAL_NOTEQUAL
, tmp_range_list(0), LEFT
, __get_cur_slist(), implied_true
, implied_false
);
450 delete_equiv_slist(implied_true
, name
, sym
);
451 delete_equiv_slist(implied_false
, name
, sym
);
456 static void get_tf_states(struct expression
*expr
,
457 struct state_list
**implied_true
,
458 struct state_list
**implied_false
)
460 if (expr
->type
== EXPR_COMPARE
)
461 handle_comparison(expr
, implied_true
, implied_false
);
463 handle_zero_comparison(expr
, implied_true
, implied_false
);
466 static void implied_states_hook(struct expression
*expr
)
469 struct state_list
*implied_true
= NULL
;
470 struct state_list
*implied_false
= NULL
;
472 if (option_no_implied
)
475 get_tf_states(expr
, &implied_true
, &implied_false
);
477 FOR_EACH_PTR(implied_true
, sm
) {
478 __set_true_false_sm(sm
, NULL
);
479 } END_FOR_EACH_PTR(sm
);
480 free_slist(&implied_true
);
482 FOR_EACH_PTR(implied_false
, sm
) {
483 __set_true_false_sm(NULL
, sm
);
484 } END_FOR_EACH_PTR(sm
);
485 free_slist(&implied_false
);
488 struct range_list
*__get_implied_values(struct expression
*switch_expr
)
492 struct smatch_state
*state
;
493 struct range_list
*ret
= NULL
;
495 name
= get_variable_from_expr(switch_expr
, &sym
);
498 state
= get_state(SMATCH_EXTRA
, name
, sym
);
501 ret
= clone_range_list(get_dinfo(state
)->value_ranges
);
505 add_range(&ret
, whole_range
.min
, whole_range
.max
);
509 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
510 struct expression
*case_expr
,
511 struct range_list_stack
**remaining_cases
,
512 struct state_list
**raw_slist
)
517 struct sm_state
*true_sm
;
518 struct state_list
*true_states
= NULL
;
519 struct state_list
*false_states
= NULL
;
520 struct state_list
*ret
= clone_slist(*raw_slist
);
522 struct data_range
*range
;
523 struct range_list
*vals
= NULL
;
525 name
= get_variable_from_expr(switch_expr
, &sym
);
528 sm
= get_sm_state_slist(*raw_slist
, SMATCH_EXTRA
, name
, sym
);
530 vals
= top_range_list(*remaining_cases
);
532 if (!get_value(case_expr
, &val
)) {
535 filter_top_range_list(remaining_cases
, val
);
536 range
= alloc_range(val
, val
);
537 add_ptr_list(&vals
, range
);
541 separate_and_filter(sm
, SPECIAL_EQUAL
, vals
, LEFT
, *raw_slist
, &true_states
, &false_states
);
543 true_sm
= get_sm_state_slist(true_states
, SMATCH_EXTRA
, name
, sym
);
545 set_state_slist(&true_states
, SMATCH_EXTRA
, name
, sym
, alloc_extra_state_range_list(vals
));
546 overwrite_slist(true_states
, &ret
);
547 free_slist(&true_states
);
548 free_slist(&false_states
);
554 static void match_end_func(struct symbol
*sym
)
556 implied_debug_msg
= NULL
;
560 * get_implications() can be called by check_ scripts.
562 void get_implications(char *name
, struct symbol
*sym
, int comparison
, long long num
,
563 struct state_list
**true_states
,
564 struct state_list
**false_states
)
568 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
571 if (slist_has_state(sm
->possible
, &undefined
))
573 separate_and_filter(sm
, comparison
, tmp_range_list(num
), LEFT
, __get_cur_slist(), true_states
, false_states
);
576 void __extra_match_condition(struct expression
*expr
);
577 void register_implications(int id
)
579 add_hook(&implied_states_hook
, CONDITION_HOOK
);
580 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
581 add_hook(&match_end_func
, END_FUNC_HOOK
);