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 print_once
= 0;
61 static int pool_in_pools(struct state_list
*pool
,
62 struct state_list_stack
*pools
)
64 struct state_list
*tmp
;
66 FOR_EACH_PTR(pools
, tmp
) {
71 } END_FOR_EACH_PTR(tmp
);
75 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
76 struct state_list_stack
*pools
, int *modified
)
78 struct sm_state
*ret
= NULL
;
79 struct sm_state
*left
;
80 struct sm_state
*right
;
86 if (sm
->nr_children
> 5000) {
88 smatch_msg("debug: remove_my_pools %s nr_children %d",
89 sm
->name
, sm
->nr_children
);
94 if (pool_in_pools(sm
->my_pool
, pools
)) {
95 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
96 show_state(sm
->state
), sm
->line
);
101 if (!is_merged(sm
)) {
102 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
107 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
108 left
= remove_my_pools(sm
->pre_left
, pools
, &removed
);
109 right
= remove_my_pools(sm
->pre_right
, pools
, &removed
);
111 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
115 if (!left
&& !right
) {
116 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
121 ret
= clone_state(right
);
123 ret
->pre_right
= right
;
124 ret
->pre_left
= NULL
;
125 ret
->my_pool
= sm
->my_pool
;
127 ret
= clone_state(left
);
129 ret
->pre_left
= left
;
130 ret
->pre_right
= NULL
;
131 ret
->my_pool
= sm
->my_pool
;
133 ret
= merge_sm_states(left
, right
);
134 ret
->my_pool
= sm
->my_pool
;
137 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
141 static struct state_list
*filter_stack(struct state_list
*pre_list
,
142 struct state_list_stack
*stack
)
144 struct state_list
*ret
= NULL
;
145 struct sm_state
*tmp
;
146 struct sm_state
*filtered_state
;
153 FOR_EACH_PTR(pre_list
, tmp
) {
155 filtered_state
= remove_my_pools(tmp
, stack
, &modified
);
156 if (filtered_state
&& modified
) {
157 add_ptr_list(&ret
, filtered_state
);
158 if ((counter
++)%10 && out_of_memory())
162 } END_FOR_EACH_PTR(tmp
);
166 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
168 struct sm_state
*tmp
;
170 FOR_EACH_PTR(checked
, tmp
) {
173 } END_FOR_EACH_PTR(tmp
);
177 static void separate_pools(struct sm_state
*sm_state
, int comparison
, int num
,
179 struct state_list_stack
**true_stack
,
180 struct state_list_stack
**false_stack
,
181 struct state_list
**checked
)
185 int free_checked
= 0;
186 struct state_list
*checked_states
= NULL
;
192 Sometimes the implications are just too big to deal with
193 so we bail. Theoretically, implications only get rid of
194 false positives and don't affect actual bugs.
196 if (sm_state
->nr_children
> 5000) {
198 smatch_msg("debug: seperate_pools %s nr_children %d",
199 sm_state
->name
, sm_state
->nr_children
);
204 if (checked
== NULL
) {
205 checked
= &checked_states
;
208 if (is_checked(*checked
, sm_state
)) {
211 add_ptr_list(checked
, sm_state
);
213 if (sm_state
->my_pool
) {
214 if (is_implied(sm_state
)) {
215 s
= get_sm_state_slist(sm_state
->my_pool
,
216 sm_state
->name
, sm_state
->owner
,
222 istrue
= !possibly_false(comparison
,
223 (struct data_info
*)s
->state
->data
, num
,
225 isfalse
= !possibly_true(comparison
,
226 (struct data_info
*)s
->state
->data
,
229 if (debug_implied_states
|| debug_states
) {
230 if (istrue
&& isfalse
) {
231 printf("'%s = %s' from %d does not exist.\n",
232 s
->name
, show_state(s
->state
),
235 printf("'%s = %s' from %d is true.\n",
236 s
->name
, show_state(s
->state
),
238 } else if (isfalse
) {
239 printf("'%s = %s' from %d is false.\n",
240 s
->name
, show_state(s
->state
),
243 printf("'%s = %s' from %d could be true or "
245 show_state(s
->state
), s
->line
);
249 add_pool(true_stack
, s
->my_pool
);
252 add_pool(false_stack
, s
->my_pool
);
255 separate_pools(sm_state
->pre_left
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
256 separate_pools(sm_state
->pre_right
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
261 static void get_eq_neq(struct sm_state
*sm_state
, int comparison
, int num
,
263 struct state_list
*pre_list
,
264 struct state_list
**true_states
,
265 struct state_list
**false_states
)
267 struct state_list_stack
*true_stack
= NULL
;
268 struct state_list_stack
*false_stack
= NULL
;
270 if (debug_implied_states
|| debug_states
) {
272 smatch_msg("checking implications: (%s %s %d)",
273 sm_state
->name
, show_special(comparison
), num
);
275 smatch_msg("checking implications: (%d %s %s)",
276 num
, show_special(comparison
), sm_state
->name
);
279 separate_pools(sm_state
, comparison
, num
, left
, &true_stack
, &false_stack
, NULL
);
281 DIMPLIED("filtering true stack.\n");
282 *true_states
= filter_stack(pre_list
, false_stack
);
283 DIMPLIED("filtering false stack.\n");
284 *false_states
= filter_stack(pre_list
, true_stack
);
285 free_stack(&true_stack
);
286 free_stack(&false_stack
);
287 if (debug_implied_states
|| debug_states
) {
288 printf("These are the implied states for the true path:\n");
289 __print_slist(*true_states
);
290 printf("These are the implied states for the false path:\n");
291 __print_slist(*false_states
);
295 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
297 expr
= strip_expr(expr
);
298 if (expr
->type
== EXPR_ASSIGNMENT
)
299 return get_implication_variable(expr
->left
, symp
);
300 return get_variable_from_expr(expr
, symp
);
303 static void handle_comparison(struct expression
*expr
,
304 struct state_list
**implied_true
,
305 struct state_list
**implied_false
)
309 struct sm_state
*state
;
313 value
= get_value(expr
->left
);
314 if (value
== UNDEFINED
) {
315 value
= get_value(expr
->right
);
316 if (value
== UNDEFINED
)
321 name
= get_implication_variable(expr
->left
, &sym
);
323 name
= get_implication_variable(expr
->right
, &sym
);
326 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
329 if (!is_merged(state
)) {
330 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), state
->name
);
333 get_eq_neq(state
, expr
->op
, value
, left
, __get_cur_slist(), implied_true
, implied_false
);
334 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
335 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
340 static void get_tf_states(struct expression
*expr
,
341 struct state_list
**implied_true
,
342 struct state_list
**implied_false
)
346 struct sm_state
*state
;
348 if (expr
->type
== EXPR_COMPARE
) {
349 handle_comparison(expr
, implied_true
, implied_false
);
352 if (expr
->type
== EXPR_ASSIGNMENT
) {
353 /* most of the time ->my_pools will be empty here because we
354 just set the state, but if have assigned a conditional
355 function there are implications. */
359 name
= get_variable_from_expr(expr
, &sym
);
362 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
365 if (!is_merged(state
)) {
366 DIMPLIED("%d '%s' has no pools.\n", get_lineno(), state
->name
);
369 get_eq_neq(state
, SPECIAL_NOTEQUAL
, 0, 1, __get_cur_slist(), implied_true
, implied_false
);
370 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
371 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
376 static void implied_states_hook(struct expression
*expr
)
378 struct sm_state
*state
;
379 struct state_list
*implied_true
= NULL
;
380 struct state_list
*implied_false
= NULL
;
382 if (option_no_implied
)
385 get_tf_states(expr
, &implied_true
, &implied_false
);
387 FOR_EACH_PTR(implied_true
, state
) {
388 __set_true_false_sm(state
, NULL
);
389 } END_FOR_EACH_PTR(state
);
390 free_slist(&implied_true
);
392 FOR_EACH_PTR(implied_false
, state
) {
393 __set_true_false_sm(NULL
, state
);
394 } END_FOR_EACH_PTR(state
);
395 free_slist(&implied_false
);
398 void get_implications(char *name
, struct symbol
*sym
, int comparison
, int num
,
399 struct state_list
**true_states
,
400 struct state_list
**false_states
)
404 sm
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
407 if (slist_has_state(sm
->possible
, &undefined
))
409 get_eq_neq(sm
, comparison
, num
, 1, __get_cur_slist(), true_states
, false_states
);
412 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
413 struct expression
*case_expr
,
414 struct state_list
**raw_slist
)
419 struct sm_state
*true_sm
;
420 struct sm_state
*false_sm
;
421 struct state_list
*true_states
= NULL
;
422 struct state_list
*false_states
= NULL
;
423 struct state_list
*ret
= clone_slist(*raw_slist
);
428 name
= get_variable_from_expr(switch_expr
, &sym
);
431 sm
= get_sm_state_slist(*raw_slist
, name
, SMATCH_EXTRA
, sym
);
432 val
= get_value(case_expr
);
433 if (val
== UNDEFINED
)
436 get_eq_neq(sm
, SPECIAL_EQUAL
, val
, 1, *raw_slist
, &true_states
, &false_states
);
439 true_sm
= get_sm_state_slist(true_states
, name
, SMATCH_EXTRA
, sym
);
441 set_state_slist(&true_states
, name
, SMATCH_EXTRA
, sym
, alloc_extra_state(val
));
442 false_sm
= get_sm_state_slist(false_states
, name
, SMATCH_EXTRA
, sym
);
444 set_state_slist(&false_states
, name
, SMATCH_EXTRA
, sym
, add_filter(sm
?sm
->state
:NULL
, val
));
445 overwrite_slist(false_states
, raw_slist
);
446 overwrite_slist(true_states
, &ret
);
447 free_slist(&true_states
);
448 free_slist(&false_states
);
454 static void clear_print_once(struct symbol
*sym
)
459 void __extra_match_condition(struct expression
*expr
);
460 void register_implications(int id
)
462 add_hook(&implied_states_hook
, CONDITION_HOOK
);
463 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
464 add_hook(&clear_print_once
, END_FUNC_HOOK
);