2 * Copyright (C) 2014 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * Keep a record of all the things we have tested for so that we know when we
20 * test for it again. For example, if we have code like this:
30 * That's the end goal at least. But actually implementing the flow of that
31 * requires quite a bit of work because if "foo" changes the condition needs to
32 * be retested and smatch_implications.c needs to be updated.
34 * For now, I just record the conditions and use it to see if we test for NULL
40 #include "smatch_slist.h"
45 static struct smatch_state
*alloc_link_state(struct string_list
*links
)
47 struct smatch_state
*state
;
52 state
= __alloc_smatch_state(0);
55 FOR_EACH_PTR(links
, tmp
) {
57 snprintf(buf
, sizeof(buf
), "%s", tmp
);
59 append(buf
, ", ", sizeof(buf
));
60 append(buf
, tmp
, sizeof(buf
));
62 } END_FOR_EACH_PTR(tmp
);
64 state
->name
= alloc_sname(buf
);
69 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
71 struct smatch_state
*ret
;
72 struct string_list
*links
;
74 links
= combine_string_lists(s1
->data
, s2
->data
);
75 ret
= alloc_link_state(links
);
79 static void save_link_var_sym(const char *var
, struct symbol
*sym
, const char *link
)
81 struct smatch_state
*old_state
, *new_state
;
82 struct string_list
*links
;
85 old_state
= get_state(link_id
, var
, sym
);
87 links
= clone_str_list(old_state
->data
);
91 new = alloc_sname(link
);
92 insert_string(&links
, new);
94 new_state
= alloc_link_state(links
);
95 set_state(link_id
, var
, sym
, new_state
);
98 static void match_link_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
100 struct string_list
*links
;
103 links
= sm
->state
->data
;
105 FOR_EACH_PTR(links
, tmp
) {
106 set_state(my_id
, tmp
, NULL
, &undefined
);
107 } END_FOR_EACH_PTR(tmp
);
108 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
111 static struct smatch_state
*alloc_state(struct expression
*expr
, int is_true
)
113 struct smatch_state
*state
;
115 state
= __alloc_smatch_state(0);
117 state
->name
= alloc_sname("true");
119 state
->name
= alloc_sname("false");
124 static void store_all_links(struct expression
*expr
, const char *condition
)
129 expr
= strip_expr(expr
);
131 if (is_array(expr
)) {
132 var
= expr_to_known_chunk_sym(expr
, &sym
);
134 save_link_var_sym(var
, sym
, condition
);
137 switch (expr
->type
) {
140 store_all_links(expr
->left
, condition
);
141 store_all_links(expr
->right
, condition
);
147 var
= expr_to_var_sym(expr
, &sym
);
150 save_link_var_sym(var
, sym
, condition
);
155 static int condition_too_complicated(struct expression
*expr
)
157 if (get_complication_score(expr
) > 2)
163 void __stored_condition(struct expression
*expr
)
165 struct smatch_state
*true_state
, *false_state
;
169 if (get_implied_value(expr
, &val
))
172 if (condition_too_complicated(expr
))
175 name
= expr_to_str(expr
);
178 true_state
= alloc_state(expr
, TRUE
);
179 false_state
= alloc_state(expr
, FALSE
);
180 set_true_false_states(my_id
, name
, NULL
, true_state
, false_state
);
181 store_all_links(expr
, alloc_sname(name
));
185 struct smatch_state
*get_stored_condition(struct expression
*expr
)
187 struct smatch_state
*state
;
190 name
= expr_to_str(expr
);
194 state
= get_state(my_id
, name
, NULL
);
199 void register_stored_conditions(int id
)
204 void register_stored_conditions_links(int id
)
207 add_merge_hook(link_id
, &merge_links
);
208 add_modification_hook(link_id
, &match_link_modify
);
211 #define RECURSE_LIMIT 50
213 static void filter_by_sm(struct sm_state
*sm
,
214 struct stree_stack
**true_stack
,
215 struct stree_stack
**false_stack
,
221 if ((*recurse_cnt
)++ > RECURSE_LIMIT
)
224 if (strcmp(sm
->state
->name
, "true") == 0) {
225 add_pool(true_stack
, sm
->pool
);
226 } else if (strcmp(sm
->state
->name
, "false") == 0) {
227 add_pool(false_stack
, sm
->pool
);
231 filter_by_sm(sm
->left
, true_stack
, false_stack
, recurse_cnt
);
232 filter_by_sm(sm
->right
, true_stack
, false_stack
, recurse_cnt
);
236 struct sm_state
*stored_condition_implication_hook(struct expression
*expr
,
237 struct stree_stack
**true_stack
,
238 struct stree_stack
**false_stack
)
243 struct stree_stack
*tmp_true
= NULL
;
244 struct stree_stack
*tmp_false
= NULL
;
247 expr
= strip_expr(expr
);
250 * We only look at BINOP here because smatch_extra.c and
251 * smatch_compare.c handle everything else.
253 if (expr
->type
!= EXPR_BINOP
)
256 name
= expr_to_str(expr
);
260 sm
= get_sm_state(my_id
, name
, NULL
);
267 filter_by_sm(sm
, &tmp_true
, &tmp_false
, &recurse_cnt
);
268 if (!tmp_true
&& !tmp_false
)
270 if (recurse_cnt
> RECURSE_LIMIT
) {
275 FOR_EACH_PTR(tmp_true
, stree
) {
276 add_pool(true_stack
, stree
);
277 } END_FOR_EACH_PTR(stree
);
279 FOR_EACH_PTR(tmp_false
, stree
) {
280 add_pool(false_stack
, stree
);
281 } END_FOR_EACH_PTR(stree
);
284 free_stree_stack(&tmp_true
);
285 free_stree_stack(&tmp_false
);