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 int debug_implied_states
= 0;
60 int option_no_implied
= 0;
62 static int print_once
= 0;
64 static int pool_in_pools(struct state_list
*pool
,
65 struct state_list_stack
*pools
)
67 struct state_list
*tmp
;
69 FOR_EACH_PTR(pools
, tmp
) {
74 } END_FOR_EACH_PTR(tmp
);
78 struct sm_state
*remove_my_pools(struct sm_state
*sm
,
79 struct state_list_stack
*pools
, int *modified
)
81 struct sm_state
*ret
= NULL
;
82 struct sm_state
*left
;
83 struct sm_state
*right
;
89 if (sm
->nr_children
> 5000) {
91 smatch_msg("debug: remove_my_pools %s nr_children %d",
92 sm
->name
, sm
->nr_children
);
97 if (pool_in_pools(sm
->my_pool
, pools
)) {
98 DIMPLIED("removed %s = %s from %d\n", sm
->name
,
99 show_state(sm
->state
), sm
->line
);
104 if (!is_merged(sm
)) {
105 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
),
110 DIMPLIED("checking %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
111 left
= remove_my_pools(sm
->left
, pools
, &removed
);
112 right
= remove_my_pools(sm
->right
, pools
, &removed
);
114 DIMPLIED("kept %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
118 if (!left
&& !right
) {
119 DIMPLIED("removed %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
124 ret
= clone_state(right
);
128 ret
->my_pool
= sm
->my_pool
;
130 ret
= clone_state(left
);
134 ret
->my_pool
= sm
->my_pool
;
136 ret
= merge_sm_states(left
, right
);
137 ret
->my_pool
= sm
->my_pool
;
140 DIMPLIED("partial %s = %s from %d\n", sm
->name
, show_state(sm
->state
), sm
->line
);
144 static struct state_list
*filter_stack(struct state_list
*pre_list
,
145 struct state_list_stack
*stack
)
147 struct state_list
*ret
= NULL
;
148 struct sm_state
*tmp
;
149 struct sm_state
*filtered_state
;
156 FOR_EACH_PTR(pre_list
, tmp
) {
158 filtered_state
= remove_my_pools(tmp
, stack
, &modified
);
159 if (filtered_state
&& modified
) {
160 add_ptr_list(&ret
, filtered_state
);
161 if ((counter
++)%10 && out_of_memory())
165 } END_FOR_EACH_PTR(tmp
);
169 static int is_checked(struct state_list
*checked
, struct sm_state
*sm
)
171 struct sm_state
*tmp
;
173 FOR_EACH_PTR(checked
, tmp
) {
176 } END_FOR_EACH_PTR(tmp
);
180 static void separate_pools(struct sm_state
*sm_state
, int comparison
, int num
,
182 struct state_list_stack
**true_stack
,
183 struct state_list_stack
**false_stack
,
184 struct state_list
**checked
)
188 int free_checked
= 0;
189 struct state_list
*checked_states
= NULL
;
195 Sometimes the implications are just too big to deal with
196 so we bail. Theoretically, implications only get rid of
197 false positives and don't affect actual bugs.
199 if (sm_state
->nr_children
> 5000) {
201 smatch_msg("debug: seperate_pools %s nr_children %d",
202 sm_state
->name
, sm_state
->nr_children
);
207 if (checked
== NULL
) {
208 checked
= &checked_states
;
211 if (is_checked(*checked
, sm_state
)) {
214 add_ptr_list(checked
, sm_state
);
216 if (sm_state
->my_pool
) {
217 if (is_implied(sm_state
)) {
218 s
= get_sm_state_slist(sm_state
->my_pool
,
219 sm_state
->name
, sm_state
->owner
,
225 istrue
= !possibly_false(comparison
,
226 (struct data_info
*)s
->state
->data
, num
,
228 isfalse
= !possibly_true(comparison
,
229 (struct data_info
*)s
->state
->data
,
232 if (debug_implied_states
|| debug_states
) {
233 if (istrue
&& isfalse
) {
234 printf("'%s = %s' from %d does not exist.\n",
235 s
->name
, show_state(s
->state
),
238 printf("'%s = %s' from %d is true.\n",
239 s
->name
, show_state(s
->state
),
241 } else if (isfalse
) {
242 printf("'%s = %s' from %d is false.\n",
243 s
->name
, show_state(s
->state
),
246 printf("'%s = %s' from %d could be true or "
248 show_state(s
->state
), s
->line
);
252 add_pool(true_stack
, s
->my_pool
);
255 add_pool(false_stack
, s
->my_pool
);
258 separate_pools(sm_state
->left
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
259 separate_pools(sm_state
->right
, comparison
, num
, left
, true_stack
, false_stack
, checked
);
264 static void get_eq_neq(struct sm_state
*sm_state
, int comparison
, int num
,
266 struct state_list
*pre_list
,
267 struct state_list
**true_states
,
268 struct state_list
**false_states
)
270 struct state_list_stack
*true_stack
= NULL
;
271 struct state_list_stack
*false_stack
= NULL
;
273 if (debug_implied_states
|| debug_states
) {
275 smatch_msg("checking implications: (%s %s %d)",
276 sm_state
->name
, show_special(comparison
), num
);
278 smatch_msg("checking implications: (%d %s %s)",
279 num
, show_special(comparison
), sm_state
->name
);
282 separate_pools(sm_state
, comparison
, num
, left
, &true_stack
, &false_stack
, NULL
);
284 DIMPLIED("filtering true stack.\n");
285 *true_states
= filter_stack(pre_list
, false_stack
);
286 DIMPLIED("filtering false stack.\n");
287 *false_states
= filter_stack(pre_list
, true_stack
);
288 free_stack(&true_stack
);
289 free_stack(&false_stack
);
290 if (debug_implied_states
|| debug_states
) {
291 printf("These are the implied states for the true path:\n");
292 __print_slist(*true_states
);
293 printf("These are the implied states for the false path:\n");
294 __print_slist(*false_states
);
298 static char *get_implication_variable(struct expression
*expr
, struct symbol
**symp
)
300 expr
= strip_expr(expr
);
301 if (expr
->type
== EXPR_ASSIGNMENT
)
302 return get_implication_variable(expr
->left
, symp
);
303 return get_variable_from_expr(expr
, symp
);
306 static void handle_comparison(struct expression
*expr
,
307 struct state_list
**implied_true
,
308 struct state_list
**implied_false
)
312 struct sm_state
*state
;
316 value
= get_value(expr
->left
);
317 if (value
== UNDEFINED
) {
318 value
= get_value(expr
->right
);
319 if (value
== UNDEFINED
)
324 name
= get_implication_variable(expr
->left
, &sym
);
326 name
= get_implication_variable(expr
->right
, &sym
);
329 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
332 if (!is_merged(state
)) {
333 DIMPLIED("%d '%s' is not merged.\n", get_lineno(), state
->name
);
336 get_eq_neq(state
, expr
->op
, value
, left
, __get_cur_slist(), implied_true
, implied_false
);
337 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
338 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
343 static void get_tf_states(struct expression
*expr
,
344 struct state_list
**implied_true
,
345 struct state_list
**implied_false
)
349 struct sm_state
*state
;
351 if (expr
->type
== EXPR_COMPARE
) {
352 handle_comparison(expr
, implied_true
, implied_false
);
355 if (expr
->type
== EXPR_ASSIGNMENT
) {
356 /* most of the time ->my_pools will be empty here because we
357 just set the state, but if have assigned a conditional
358 function there are implications. */
362 name
= get_variable_from_expr(expr
, &sym
);
365 state
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
368 if (!is_merged(state
)) {
369 DIMPLIED("%d '%s' has no pools.\n", get_lineno(), state
->name
);
372 get_eq_neq(state
, SPECIAL_NOTEQUAL
, 0, 1, __get_cur_slist(), implied_true
, implied_false
);
373 delete_state_slist(implied_true
, name
, SMATCH_EXTRA
, sym
);
374 delete_state_slist(implied_false
, name
, SMATCH_EXTRA
, sym
);
379 static void implied_states_hook(struct expression
*expr
)
381 struct sm_state
*state
;
382 struct state_list
*implied_true
= NULL
;
383 struct state_list
*implied_false
= NULL
;
385 if (option_no_implied
)
388 get_tf_states(expr
, &implied_true
, &implied_false
);
390 FOR_EACH_PTR(implied_true
, state
) {
391 __set_true_false_sm(state
, NULL
);
392 } END_FOR_EACH_PTR(state
);
393 free_slist(&implied_true
);
395 FOR_EACH_PTR(implied_false
, state
) {
396 __set_true_false_sm(NULL
, state
);
397 } END_FOR_EACH_PTR(state
);
398 free_slist(&implied_false
);
401 void get_implications(char *name
, struct symbol
*sym
, int comparison
, int num
,
402 struct state_list
**true_states
,
403 struct state_list
**false_states
)
407 sm
= get_sm_state(name
, SMATCH_EXTRA
, sym
);
410 if (slist_has_state(sm
->possible
, &undefined
))
412 get_eq_neq(sm
, comparison
, num
, 1, __get_cur_slist(), true_states
, false_states
);
415 struct state_list
*__implied_case_slist(struct expression
*switch_expr
,
416 struct expression
*case_expr
,
417 struct state_list
**raw_slist
)
422 struct sm_state
*true_sm
;
423 struct sm_state
*false_sm
;
424 struct state_list
*true_states
= NULL
;
425 struct state_list
*false_states
= NULL
;
426 struct state_list
*ret
= clone_slist(*raw_slist
);
431 name
= get_variable_from_expr(switch_expr
, &sym
);
434 sm
= get_sm_state_slist(*raw_slist
, name
, SMATCH_EXTRA
, sym
);
435 val
= get_value(case_expr
);
436 if (val
== UNDEFINED
)
439 get_eq_neq(sm
, SPECIAL_EQUAL
, val
, 1, *raw_slist
, &true_states
, &false_states
);
442 true_sm
= get_sm_state_slist(true_states
, name
, SMATCH_EXTRA
, sym
);
444 set_state_slist(&true_states
, name
, SMATCH_EXTRA
, sym
, alloc_extra_state(val
));
445 false_sm
= get_sm_state_slist(false_states
, name
, SMATCH_EXTRA
, sym
);
447 set_state_slist(&false_states
, name
, SMATCH_EXTRA
, sym
, add_filter(sm
?sm
->state
:NULL
, val
));
448 overwrite_slist(false_states
, raw_slist
);
449 overwrite_slist(true_states
, &ret
);
450 free_slist(&true_states
);
451 free_slist(&false_states
);
457 static void clear_print_once(struct symbol
*sym
)
462 void __extra_match_condition(struct expression
*expr
);
463 void register_implications(int id
)
465 add_hook(&implied_states_hook
, CONDITION_HOOK
);
466 add_hook(&__extra_match_condition
, CONDITION_HOOK
);
467 add_hook(&clear_print_once
, END_FUNC_HOOK
);