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 static int print_count
= 0;
58 #define print_once(msg...) do { if (!print_count++) sm_msg(msg); } while (0)
59 #define DIMPLIED(msg...) do { if (option_debug_implied) printf(msg); } while (0)
61 int option_debug_implied
= 0;
62 int option_no_implied
= 0;
69 * It messes things up to free range list allocations. This helper fuction
70 * lets us reuse memory instead of doing new allocations.
72 static struct range_list
*tmp_range_list(long long num
)
74 static struct range_list
*my_list
= NULL
;
75 static struct data_range
*my_range
;
77 __free_ptr_list((struct ptr_list
**)&my_list
);
78 my_range
= alloc_range(num
, num
);
81 add_ptr_list(&my_list
, my_range
);
86 * If 'foo' == 99 add it that pool to the true pools. If it's false, add it to
87 * the false pools. If we're not sure, then we don't add it to either.
89 static void do_compare(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
91 struct state_list_stack
**true_stack
,
92 struct state_list_stack
**false_stack
)
98 if (!sm_state
->my_pool
)
101 if (is_implied(sm_state
)) {
102 s
= get_sm_state_slist(sm_state
->my_pool
,
103 sm_state
->owner
, sm_state
->name
,
110 if (option_debug_implied
|| option_debug
)
111 sm_msg("%s from %d, has borrowed implications.",
112 sm_state
->name
, sm_state
->line
);
116 istrue
= !possibly_false_range_list(comparison
, get_dinfo(s
->state
), vals
, lr
);
117 isfalse
= !possibly_true_range_list(comparison
, get_dinfo(s
->state
), vals
, lr
);
119 if (option_debug_implied
|| option_debug
) {
120 if (istrue
&& isfalse
) {
121 printf("'%s = %s' from %d does not exist.\n", s
->name
,
122 show_state(s
->state
), s
->line
);
124 printf("'%s = %s' from %d is true.\n", s
->name
, show_state(s
->state
),
126 } else if (isfalse
) {
127 printf("'%s = %s' from %d is false.\n", s
->name
, show_state(s
->state
),
130 printf("'%s = %s' from %d could be true or false.\n", s
->name
,
131 show_state(s
->state
), s
->line
);
135 add_pool(true_stack
, s
->my_pool
);
138 add_pool(false_stack
, s
->my_pool
);
141 static int pool_in_pools(struct state_list
*pool
,
142 struct state_list_stack
*pools
)
144 struct state_list
*tmp
;
146 FOR_EACH_PTR(pools
, tmp
) {
151 } END_FOR_EACH_PTR(tmp
);
155 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
157 struct sm_state
*tmp
;
159 FOR_EACH_PTR(checked
, tmp
) {
162 } END_FOR_EACH_PTR(tmp
);
168 * Example code: if (foo == 99) {
170 * Say 'foo' is a merged state that has many possible values. It is the combination
171 * of merges. separate_pools() iterates through the pools recursively and calls
172 * do_compare() for each time 'foo' was set.
174 static void separate_pools(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
176 struct state_list_stack
**true_stack
,
177 struct state_list_stack
**false_stack
,
178 struct state_list
**checked
)
180 int free_checked
= 0;
181 struct state_list
*checked_states
= NULL
;
187 Sometimes the implications are just too big to deal with
188 so we bail. Theoretically, bailing out here can cause more false
189 positives but won't hide actual bugs.
191 if (sm_state
->nr_children
> 4000) {
192 print_once("debug: seperate_pools %s nr_children %d", sm_state
->name
,
193 sm_state
->nr_children
);
197 if (checked
== NULL
) {
198 checked
= &checked_states
;
201 if (is_checked(*checked
, sm_state
))
203 add_ptr_list(checked
, sm_state
);
205 do_compare(sm_state
, comparison
, vals
, lr
, true_stack
, false_stack
);
207 separate_pools(sm_state
->left
, comparison
, vals
, lr
, true_stack
, false_stack
, checked
);
208 separate_pools(sm_state
->right
, comparison
, vals
, lr
, true_stack
, false_stack
, checked
);
213 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
214 struct state_list_stack
*pools
, int *modified
)
216 struct sm_state
*ret
= NULL
;
217 struct sm_state
*left
;
218 struct sm_state
*right
;
224 if (sm
->nr_children
> 4000) {
225 print_once("debug: remove_my_pools %s nr_children %d", sm
->name
,
230 if (pool_in_pools(sm
->my_pool
, pools
)) {
231 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
232 show_state(sm
->state
), sm
->line
);
237 if (!is_merged(sm
)) {
238 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
243 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
244 left
= remove_my_pools(sm
->left
, pools
, &removed
);
245 right
= remove_my_pools(sm
->right
, pools
, &removed
);
247 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
251 if (!left
&& !right
) {
252 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
257 ret
= clone_sm(right
);
261 ret
->my_pool
= sm
->my_pool
;
263 ret
= clone_sm(left
);
267 ret
->my_pool
= sm
->my_pool
;
269 ret
= merge_sm_states(left
, right
);
270 ret
->my_pool
= sm
->my_pool
;
273 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
277 static struct state_list
*filter_stack(struct state_list
*pre_list
,
278 struct state_list_stack
*stack
)
280 struct state_list
*ret
= NULL
;
281 struct sm_state
*tmp
;
282 struct sm_state
*filtered_sm
;
289 FOR_EACH_PTR(pre_list
, tmp
) {
291 filtered_sm
= remove_my_pools(tmp
, stack
, &modified
);
292 if (filtered_sm
&& modified
) {
293 filtered_sm
->name
= tmp
->name
;
294 filtered_sm
->sym
= tmp
->sym
;
295 add_ptr_list(&ret
, filtered_sm
);
296 if ((counter
++)%10 && out_of_memory())
300 } END_FOR_EACH_PTR(tmp
);
304 static void separate_and_filter(struct sm_state
*sm_state
, int comparison
, struct range_list
*vals
,
306 struct state_list
*pre_list
,
307 struct state_list
**true_states
,
308 struct state_list
**false_states
)
310 struct state_list_stack
*true_stack
= NULL
;
311 struct state_list_stack
*false_stack
= NULL
;
312 struct timeval time_before
;
313 struct timeval time_after
;
315 gettimeofday(&time_before
, NULL
);
317 if (!is_merged(sm_state
)) {
318 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), sm_state
->name
);
322 if (option_debug_implied
|| option_debug
) {
324 sm_msg("checking implications: (%s %s %s)",
325 sm_state
->name
, show_special(comparison
), show_ranges(vals
));
327 sm_msg("checking implications: (%s %s %s)",
328 show_ranges(vals
), show_special(comparison
), sm_state
->name
);
331 separate_pools(sm_state
, comparison
, vals
, lr
, &true_stack
, &false_stack
, NULL
);
333 DIMPLIED("filtering true stack.\n");
334 *true_states
= filter_stack(pre_list
, false_stack
);
335 DIMPLIED("filtering false stack.\n");
336 *false_states
= filter_stack(pre_list
, true_stack
);
337 free_stack(&true_stack
);
338 free_stack(&false_stack
);
339 if (option_debug_implied
|| option_debug
) {
340 printf("These are the implied states for the true path:\n");
341 __print_slist(*true_states
);
342 printf("These are the implied states for the false path:\n");
343 __print_slist(*false_states
);
346 gettimeofday(&time_after
, NULL
);
347 if (time_after
.tv_sec
- time_before
.tv_sec
> 7)
348 __bail_on_rest_of_function
= 1;
351 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
353 expr
= strip_expr(expr
);
354 if (expr
->type
== EXPR_ASSIGNMENT
)
355 return get_implication_variable(expr
->left
, symp
);
356 return get_variable_from_expr(expr
, symp
);
359 static int get_known_value(struct expression
*expr
, long long *val
)
363 if (get_value(expr
, val
))
365 sm
= get_sm_state_expr(SMATCH_EXTRA
, expr
);
368 if (!get_single_value_from_dinfo(get_dinfo(sm
->state
), val
))
375 static void delete_equiv_slist(struct state_list
**slist
, const char *name
, struct symbol
*sym
)
377 struct smatch_state
*state
;
378 struct data_info
*dinfo
;
379 struct tracker
*tracker
;
381 state
= get_state(SMATCH_EXTRA
, name
, sym
);
382 dinfo
= get_dinfo(state
);
384 delete_state_slist(slist
, SMATCH_EXTRA
, name
, sym
);
388 FOR_EACH_PTR(dinfo
->equiv
, tracker
) {
389 delete_state_slist(slist
, SMATCH_EXTRA
, tracker
->name
, tracker
->sym
);
390 } END_FOR_EACH_PTR(tracker
);
393 static void handle_comparison(struct expression
*expr
,
394 struct state_list
**implied_true
,
395 struct state_list
**implied_false
)
403 if (get_known_value(expr
->right
, &value
))
405 else if (get_known_value(expr
->left
, &value
))
411 name
= get_implication_variable(expr
->left
, &sym
);
413 name
= get_implication_variable(expr
->right
, &sym
);
417 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
421 separate_and_filter(sm
, expr
->op
, tmp_range_list(value
), lr
, __get_cur_slist(), implied_true
, implied_false
);
422 delete_equiv_slist(implied_true
, name
, sym
);
423 delete_equiv_slist(implied_false
, name
, sym
);
428 static void handle_zero_comparison(struct expression
*expr
,
429 struct state_list
**implied_true
,
430 struct state_list
**implied_false
)
436 if (expr
->type
== EXPR_POSTOP
)
437 expr
= strip_expr(expr
->unop
);
439 if (expr
->type
== EXPR_ASSIGNMENT
) {
440 /* most of the time ->my_pools will be empty here because we
441 just set the state, but if have assigned a conditional
442 function there are implications. */
446 name
= get_variable_from_expr(expr
, &sym
);
449 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
453 separate_and_filter(sm
, SPECIAL_NOTEQUAL
, tmp_range_list(0), LEFT
, __get_cur_slist(), implied_true
, implied_false
);
454 delete_equiv_slist(implied_true
, name
, sym
);
455 delete_equiv_slist(implied_false
, name
, sym
);
460 static void get_tf_states(struct expression
*expr
,
461 struct state_list
**implied_true
,
462 struct state_list
**implied_false
)
464 if (expr
->type
== EXPR_COMPARE
)
465 handle_comparison(expr
, implied_true
, implied_false
);
467 handle_zero_comparison(expr
, implied_true
, implied_false
);
470 static void implied_states_hook(struct expression
*expr
)
473 struct state_list
*implied_true
= NULL
;
474 struct state_list
*implied_false
= NULL
;
476 if (option_no_implied
)
479 get_tf_states(expr
, &implied_true
, &implied_false
);
481 FOR_EACH_PTR(implied_true
, sm
) {
482 __set_true_false_sm(sm
, NULL
);
483 } END_FOR_EACH_PTR(sm
);
484 free_slist(&implied_true
);
486 FOR_EACH_PTR(implied_false
, sm
) {
487 __set_true_false_sm(NULL
, sm
);
488 } END_FOR_EACH_PTR(sm
);
489 free_slist(&implied_false
);
492 struct range_list
*__get_implied_values(struct expression
*switch_expr
)
496 struct smatch_state
*state
;
497 struct range_list
*ret
= NULL
;
499 name
= get_variable_from_expr(switch_expr
, &sym
);
502 state
= get_state(SMATCH_EXTRA
, name
, sym
);
505 ret
= clone_range_list(get_dinfo(state
)->value_ranges
);
509 add_range(&ret
, whole_range
.min
, whole_range
.max
);
513 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
514 struct expression
*case_expr
,
515 struct range_list_stack
**remaining_cases
,
516 struct state_list
**raw_slist
)
521 struct sm_state
*true_sm
;
522 struct state_list
*true_states
= NULL
;
523 struct state_list
*false_states
= NULL
;
524 struct state_list
*ret
= clone_slist(*raw_slist
);
526 struct data_range
*range
;
527 struct range_list
*vals
= NULL
;
529 name
= get_variable_from_expr(switch_expr
, &sym
);
532 sm
= get_sm_state_slist(*raw_slist
, SMATCH_EXTRA
, name
, sym
);
534 vals
= top_range_list(*remaining_cases
);
536 if (!get_value(case_expr
, &val
)) {
539 filter_top_range_list(remaining_cases
, val
);
540 range
= alloc_range(val
, val
);
541 add_ptr_list(&vals
, range
);
545 separate_and_filter(sm
, SPECIAL_EQUAL
, vals
, LEFT
, *raw_slist
, &true_states
, &false_states
);
547 true_sm
= get_sm_state_slist(true_states
, SMATCH_EXTRA
, name
, sym
);
549 set_state_slist(&true_states
, SMATCH_EXTRA
, name
, sym
, alloc_extra_state_range_list(vals
));
550 overwrite_slist(true_states
, &ret
);
551 free_slist(&true_states
);
552 free_slist(&false_states
);
558 static void match_end_func(struct symbol
*sym
)
564 * get_implications() can be called by check_ scripts.
566 void get_implications(char *name
, struct symbol
*sym
, int comparison
, long long num
,
567 struct state_list
**true_states
,
568 struct state_list
**false_states
)
572 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
575 if (slist_has_state(sm
->possible
, &undefined
))
577 separate_and_filter(sm
, comparison
, tmp_range_list(num
), LEFT
, __get_cur_slist(), true_states
, false_states
);
580 void __extra_match_condition(struct expression
*expr
);
581 void register_implications(int id
)
583 add_hook(&implied_states_hook
, CONDITION_HOOK
);
584 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
585 add_hook(&match_end_func
, END_FUNC_HOOK
);