2 * Copyright (C) 2012 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 * The PARAM_LIMIT code is for functions like this:
23 * if (a >= 0 && a < 10) {
30 * If frob() returns 1, then we know that a must have been in the 0-9 range
31 * at the start. Or if we return 0 then a is outside that range. So if the
32 * caller passes a 5 then the function must return 1.
34 * The "a" variable gets set to 42 in the middle, but we don't care about
35 * that, we only care about the passed in value.
37 * Originally, this code looked at the starting stree and the final stree and
38 * asked was this variable set part way through? (Over simplification). This
39 * approach works, but the problem is that it produces too many results. For
40 * example, if we dereference a pointer then we know that it must be non-NULL.
41 * So that was recorded as a PARAM_LIMIT. Another thing is that if we have
42 * two callers and we do "if (caller_one) return true; else return false;". The
43 * if (caller_one) condition might have implications so maybe it sets twenty
44 * different states instead of just the one.
46 * These extra PARAM_LIMITs are still correct, but the problem is that they
47 * take up space in the database. Perhaps more importantly parsing PARAM_LIMITS
48 * is very expensive because we have to figure out the implications for that.
49 * (2023: idea: Parse all the PARAM_LIMITS at once instead of sequentially).
50 * The PARAM_LIMITS create a lot of sm_state history and use a lot of resources.
52 * So we need a more deliberate approach.
56 #include "smatch_extra.h"
57 #include "smatch_slist.h"
61 static struct stree
*limit_states
;
62 static struct stree
*ignore_states
;
66 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
68 struct smatch_state
*state
;
70 if (!param_was_set_var_sym(sm
->name
, sm
->sym
)) {
71 state
= __get_state(SMATCH_EXTRA
, sm
->name
, sm
->sym
);
75 return alloc_estate_whole(estate_type(sm
->state
));
78 struct smatch_state
*get_orig_estate(const char *name
, struct symbol
*sym
)
80 struct smatch_state
*state
;
82 state
= get_state(my_id
, name
, sym
);
86 state
= get_state(SMATCH_EXTRA
, name
, sym
);
89 return alloc_estate_rl(alloc_whole_rl(get_real_base_type(sym
)));
92 static struct range_list
*generify_mtag_range(struct smatch_state
*state
)
94 struct range_list
*rl
;
95 struct data_range
*drange
;
97 if (!estate_type(state
) || estate_type(state
)->type
!= SYM_PTR
)
98 return estate_rl(state
);
101 * The problem is that we get too specific on our param limits when we
102 * know exactly what pointers are passed to a function. It gets to the
103 * point where we say "pointer x will succeed, but everything else will
104 * fail." And then we introduce a new caller which passes a different
105 * pointer and it's like, "Sorry bro, that's not possible."
108 rl
= estate_rl(state
);
109 FOR_EACH_PTR(rl
, drange
) {
110 if (drange
->min
.value
!= drange
->max
.value
)
112 if (drange
->min
.value
== 0)
114 if (is_err_ptr(drange
->min
))
116 return rl_union(valid_ptr_rl
, rl
);
117 } END_FOR_EACH_PTR(drange
);
119 return estate_rl(state
);
122 static bool sm_was_set(struct sm_state
*sm
)
124 struct relation
*rel
;
126 if (!estate_related(sm
->state
))
127 return param_was_set_var_sym(sm
->name
, sm
->sym
);
129 FOR_EACH_PTR(estate_related(sm
->state
), rel
) {
130 if (param_was_set_var_sym(sm
->name
, sm
->sym
))
132 } END_FOR_EACH_PTR(rel
);
136 static bool is_boring_pointer_info(const char *name
, struct range_list
*rl
)
140 /* addresses are always boring */
145 * One way that PARAM_LIMIT can be set is by dereferencing pointers.
146 * It's not necessarily very valuable to track that a pointer must
147 * be non-NULL. It's even less valuable to know that it's either NULL
148 * or valid. It can be nice to know that it's not an error pointer, I
149 * suppose. But let's not pass that data back to all the callers
154 if (strlen(name
) < 40)
157 rl_str
= show_rl(rl
);
161 if (strcmp(rl_str
, "4096-ptr_max") == 0 ||
162 strcmp(rl_str
, "0,4096-ptr_max") == 0)
168 static void print_return_value_param(int return_id
, char *return_ranges
, struct expression
*expr
)
170 struct smatch_state
*state
, *old
;
171 struct sm_state
*tmp
;
172 struct range_list
*rl
;
173 const char *orig_name
, *key
;
177 FOR_EACH_MY_SM(SMATCH_EXTRA
, __get_cur_stree(), tmp
) {
178 if (tmp
->name
[0] == '&')
181 if (!get_state_stree(limit_states
, my_id
, tmp
->name
, tmp
->sym
) &&
182 get_state_stree(ignore_states
, my_id
, tmp
->name
, tmp
->sym
))
185 orig_name
= get_param_var_sym_var_sym(tmp
->name
, tmp
->sym
, NULL
, &sym
);
186 if (!orig_name
|| !sym
)
188 param
= get_param_key_from_var_sym(orig_name
, sym
, NULL
, &key
);
192 state
= __get_state(my_id
, orig_name
, sym
);
199 if (estate_is_whole(state
) || estate_is_empty(state
))
201 old
= get_state_stree(get_start_states(), SMATCH_EXTRA
, tmp
->name
, tmp
->sym
);
202 if (old
&& rl_equiv(estate_rl(old
), estate_rl(state
)))
205 if (is_ignored_kernel_data(key
))
208 rl
= generify_mtag_range(state
);
209 if (is_boring_pointer_info(key
, rl
))
212 sql_insert_return_states(return_id
, return_ranges
, PARAM_LIMIT
,
213 param
, key
, show_rl(rl
));
214 } END_FOR_EACH_SM(tmp
);
217 static void extra_mod_hook(const char *name
, struct symbol
*sym
, struct expression
*expr
, struct smatch_state
*state
)
219 struct smatch_state
*orig
;
220 struct symbol
*param_sym
;
223 if (expr
&& expr
->smatch_flags
& Fake
)
226 param_name
= get_param_var_sym_var_sym(name
, sym
, NULL
, ¶m_sym
);
227 if (!param_name
|| !param_sym
)
229 if (get_param_num_from_sym(param_sym
) < 0)
233 if (get_state(my_id
, param_name
, param_sym
))
239 orig
= get_state(SMATCH_EXTRA
, param_name
, param_sym
);
241 orig
= alloc_estate_whole(estate_type(state
));
243 set_state(my_id
, param_name
, param_sym
, orig
);
245 free_string(param_name
);
248 static void extra_nomod_hook(const char *name
, struct symbol
*sym
, struct expression
*expr
, struct smatch_state
*state
)
251 set_state_stree(&ignore_states
, my_id
, name
, sym
, &undefined
);
254 set_state_stree(&limit_states
, my_id
, name
, sym
, &undefined
);
257 static void match_end_func(struct symbol
*sym
)
259 free_stree(&ignore_states
);
260 free_stree(&limit_states
);
263 void register_param_limit(int id
)
267 add_function_data((unsigned long *)&limit_states
);
268 add_function_data((unsigned long *)&ignore_states
);
269 add_hook(&match_end_func
, END_FUNC_HOOK
);
271 db_ignore_states(my_id
);
272 set_dynamic_states(my_id
);
274 add_extra_mod_hook(&extra_mod_hook
);
275 add_extra_nomod_hook(&extra_nomod_hook
);
276 add_unmatched_state_hook(my_id
, &unmatched_state
);
277 add_merge_hook(my_id
, &merge_estates
);
279 add_split_return_callback(&print_return_value_param
);