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_lr(comparison
, get_dinfo(s
->state
), vals
, lr
);
117 isfalse
= !possibly_true_range_list_lr(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 struct sm_state
*get_left_most_sm(struct expression
*expr
)
353 expr
= strip_expr(expr
);
354 if (expr
->type
== EXPR_ASSIGNMENT
)
355 return get_left_most_sm(expr
->left
);
356 return get_sm_state_expr(SMATCH_EXTRA
, expr
);
359 static int is_merged_expr(struct expression
*expr
)
364 if (get_value(expr
, &dummy
))
366 sm
= get_sm_state_expr(SMATCH_EXTRA
, expr
);
374 static void delete_equiv_slist(struct state_list
**slist
, const char *name
, struct symbol
*sym
)
376 struct smatch_state
*state
;
377 struct data_info
*dinfo
;
378 struct relation
*rel
;
380 state
= get_state(SMATCH_EXTRA
, name
, sym
);
381 dinfo
= get_dinfo(state
);
382 if (!dinfo
->related
) {
383 delete_state_slist(slist
, SMATCH_EXTRA
, name
, sym
);
387 FOR_EACH_PTR(dinfo
->related
, rel
) {
388 delete_state_slist(slist
, SMATCH_EXTRA
, rel
->name
, rel
->sym
);
389 } END_FOR_EACH_PTR(rel
);
392 static void handle_comparison(struct expression
*expr
,
393 struct state_list
**implied_true
,
394 struct state_list
**implied_false
)
396 struct sm_state
*sm
= NULL
;
397 struct range_list
*ranges
= NULL
;
400 if (is_merged_expr(expr
->left
)) {
402 sm
= get_left_most_sm(expr
->left
);
403 ranges
= get_range_list(expr
->right
);
404 } else if (is_merged_expr(expr
->right
)) {
406 sm
= get_left_most_sm(expr
->right
);
407 ranges
= get_range_list(expr
->left
);
410 if (!ranges
|| !sm
) {
411 free_range_list(&ranges
);
415 separate_and_filter(sm
, expr
->op
, ranges
, lr
, __get_cur_slist(), implied_true
, implied_false
);
416 free_range_list(&ranges
);
417 delete_equiv_slist(implied_true
, sm
->name
, sm
->sym
);
418 delete_equiv_slist(implied_false
, sm
->name
, sm
->sym
);
421 static void handle_zero_comparison(struct expression
*expr
,
422 struct state_list
**implied_true
,
423 struct state_list
**implied_false
)
429 if (expr
->type
== EXPR_POSTOP
)
430 expr
= strip_expr(expr
->unop
);
432 if (expr
->type
== EXPR_ASSIGNMENT
) {
433 /* most of the time ->my_pools will be empty here because we
434 just set the state, but if have assigned a conditional
435 function there are implications. */
439 name
= get_variable_from_expr(expr
, &sym
);
442 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
446 separate_and_filter(sm
, SPECIAL_NOTEQUAL
, tmp_range_list(0), LEFT
, __get_cur_slist(), implied_true
, implied_false
);
447 delete_equiv_slist(implied_true
, name
, sym
);
448 delete_equiv_slist(implied_false
, name
, sym
);
453 static void get_tf_states(struct expression
*expr
,
454 struct state_list
**implied_true
,
455 struct state_list
**implied_false
)
457 if (expr
->type
== EXPR_COMPARE
)
458 handle_comparison(expr
, implied_true
, implied_false
);
460 handle_zero_comparison(expr
, implied_true
, implied_false
);
463 static void implied_states_hook(struct expression
*expr
)
466 struct state_list
*implied_true
= NULL
;
467 struct state_list
*implied_false
= NULL
;
469 if (option_no_implied
)
472 get_tf_states(expr
, &implied_true
, &implied_false
);
474 FOR_EACH_PTR(implied_true
, sm
) {
475 __set_true_false_sm(sm
, NULL
);
476 } END_FOR_EACH_PTR(sm
);
477 free_slist(&implied_true
);
479 FOR_EACH_PTR(implied_false
, sm
) {
480 __set_true_false_sm(NULL
, sm
);
481 } END_FOR_EACH_PTR(sm
);
482 free_slist(&implied_false
);
485 struct range_list
*__get_implied_values(struct expression
*switch_expr
)
489 struct smatch_state
*state
;
490 struct range_list
*ret
= NULL
;
492 name
= get_variable_from_expr(switch_expr
, &sym
);
495 state
= get_state(SMATCH_EXTRA
, name
, sym
);
498 ret
= clone_range_list(get_dinfo(state
)->value_ranges
);
502 add_range(&ret
, whole_range
.min
, whole_range
.max
);
506 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
507 struct expression
*case_expr
,
508 struct range_list_stack
**remaining_cases
,
509 struct state_list
**raw_slist
)
514 struct sm_state
*true_sm
;
515 struct state_list
*true_states
= NULL
;
516 struct state_list
*false_states
= NULL
;
517 struct state_list
*ret
= clone_slist(*raw_slist
);
519 struct data_range
*range
;
520 struct range_list
*vals
= NULL
;
522 name
= get_variable_from_expr(switch_expr
, &sym
);
525 sm
= get_sm_state_slist(*raw_slist
, SMATCH_EXTRA
, name
, sym
);
527 vals
= top_range_list(*remaining_cases
);
529 if (!get_value(case_expr
, &val
)) {
532 filter_top_range_list(remaining_cases
, val
);
533 range
= alloc_range(val
, val
);
534 add_ptr_list(&vals
, range
);
538 separate_and_filter(sm
, SPECIAL_EQUAL
, vals
, LEFT
, *raw_slist
, &true_states
, &false_states
);
540 true_sm
= get_sm_state_slist(true_states
, SMATCH_EXTRA
, name
, sym
);
542 set_state_slist(&true_states
, SMATCH_EXTRA
, name
, sym
, alloc_extra_state_range_list(vals
));
543 overwrite_slist(true_states
, &ret
);
544 free_slist(&true_states
);
545 free_slist(&false_states
);
551 static void match_end_func(struct symbol
*sym
)
557 * get_implications() can be called by check_ scripts.
559 void get_implications(char *name
, struct symbol
*sym
, int comparison
, long long num
,
560 struct state_list
**true_states
,
561 struct state_list
**false_states
)
565 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
568 if (slist_has_state(sm
->possible
, &undefined
))
570 separate_and_filter(sm
, comparison
, tmp_range_list(num
), LEFT
, __get_cur_slist(), true_states
, false_states
);
573 void __extra_match_condition(struct expression
*expr
);
574 void register_implications(int id
)
576 add_hook(&implied_states_hook
, CONDITION_HOOK
);
577 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
578 add_hook(&match_end_func
, END_FUNC_HOOK
);