extra, math: rework how fuzzy max is handled
[smatch.git] / smatch_type_val.c
blob870ff5d807b861bfd6ad967a63461f8c4fe9ade1
1 /*
2 * sparse/smatch_type_val.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * The plan here is to save all the possible values store to a given struct
12 * member.
14 * We will load all the values in to the function_type_val table first then
15 * run a script on that and load all the resulting values into the type_val
16 * table.
18 * So in this file we want to take the union of everything assigned to the
19 * struct member and insert it into the function_type_val at the end.
21 * You would think that we could use smatch_modification_hooks.c or
22 * extra_modification_hook() here to get the information here but in the end we
23 * need to code everything again a third time.
27 #include "smatch.h"
28 #include "smatch_slist.h"
29 #include "smatch_extra.h"
31 static int my_id;
33 struct state_list_stack *fn_type_val_stack;
34 struct state_list *fn_type_val;
35 struct state_list *global_type_val;
37 static char *db_vals;
38 static int get_vals(void *unused, int argc, char **argv, char **azColName)
40 db_vals = alloc_string(argv[0]);
41 return 0;
44 static void match_inline_start(struct expression *expr)
46 push_slist(&fn_type_val_stack, fn_type_val);
47 fn_type_val = NULL;
50 static void match_inline_end(struct expression *expr)
52 fn_type_val = pop_slist(&fn_type_val_stack);
55 int get_db_type_rl(struct expression *expr, struct range_list **rl)
57 char *member;
58 struct range_list *tmp;
60 member = get_member_name(expr);
61 if (!member)
62 return 0;
64 db_vals = NULL;
65 run_sql(get_vals,
66 "select value from type_value where type = '%s'", member);
67 free_string(member);
68 if (!db_vals)
69 return 0;
70 str_to_rl(&llong_ctype, db_vals, &tmp);
71 tmp = cast_rl(get_type(expr), tmp);
72 if (is_whole_rl(tmp))
73 return 0;
74 *rl = tmp;
75 free_string(db_vals);
77 return 1;
81 * One of the complications is that smatch tries to free a bunch of data at the
82 * end of every function.
84 static struct data_info *clone_dinfo_perm(struct data_info *dinfo)
86 struct data_info *ret;
88 ret = malloc(sizeof(*ret));
89 ret->related = NULL;
90 ret->value_ranges = clone_rl_permanent(dinfo->value_ranges);
91 ret->hard_max = 0;
92 ret->fuzzy_max = dinfo->fuzzy_max;
93 return ret;
96 static struct smatch_state *clone_estate_perm(struct smatch_state *state)
98 struct smatch_state *ret;
100 ret = malloc(sizeof(*ret));
101 ret->name = alloc_string(state->name);
102 ret->data = clone_dinfo_perm(get_dinfo(state));
103 return ret;
106 static void set_state_slist_perm(struct state_list **slist, int owner, const char *name,
107 struct symbol *sym, struct smatch_state *state)
109 struct sm_state *sm;
111 sm = malloc(sizeof(*sm));
112 memset(sm, 0, sizeof(*sm));
113 sm->owner = owner;
114 sm->name = name;
115 sm->sym = sym;
116 sm->state = state;
118 overwrite_sm_state(slist, sm);
121 static void add_type_val(char *member, struct range_list *rl)
123 struct smatch_state *old, *add, *new;
125 member = alloc_string(member);
126 old = get_state_slist(fn_type_val, my_id, member, NULL);
127 add = alloc_estate_rl(rl);
128 if (old)
129 new = merge_estates(old, add);
130 else
131 new = add;
132 set_state_slist(&fn_type_val, my_id, member, NULL, new);
135 static void add_global_type_val(char *member, struct range_list *rl)
137 struct smatch_state *old, *add, *new;
139 member = alloc_string(member);
140 old = get_state_slist(global_type_val, my_id, member, NULL);
141 add = alloc_estate_rl(rl);
142 if (old)
143 new = merge_estates(old, add);
144 else
145 new = add;
146 new = clone_estate_perm(new);
147 set_state_slist_perm(&global_type_val, my_id, member, NULL, new);
150 static void match_assign_value(struct expression *expr)
152 char *member, *right_member;
153 struct range_list *rl;
154 struct symbol *type;
156 type = get_type(expr->left);
157 if (type && type->type == SYM_STRUCT)
158 return;
160 member = get_member_name(expr->left);
161 if (!member)
162 return;
164 /* if we're saying foo->mtu = bar->mtu then that doesn't add information */
165 right_member = get_member_name(expr->right);
166 if (right_member && strcmp(right_member, member) == 0)
167 goto free;
169 if (expr->op != '=') {
170 add_type_val(member, alloc_whole_rl(get_type(expr->left)));
171 goto free;
173 get_absolute_rl(expr->right, &rl);
174 rl = cast_rl(type, rl);
175 add_type_val(member, rl);
176 free:
177 free_string(right_member);
178 free_string(member);
182 * If we too: int *p = &my_struct->member then abandon all hope of tracking
183 * my_struct->member.
185 static void match_assign_pointer(struct expression *expr)
187 struct expression *right;
188 char *member;
189 struct range_list *rl;
190 struct symbol *type;
192 right = strip_expr(expr->right);
193 if (right->type != EXPR_PREOP || right->op != '&')
194 return;
195 right = strip_expr(right->unop);
197 member = get_member_name(right);
198 if (!member)
199 return;
200 type = get_type(right);
201 rl = alloc_whole_rl(type);
202 add_type_val(member, rl);
203 free_string(member);
206 static void match_global_assign(struct expression *expr)
208 char *member;
209 struct range_list *rl;
211 member = get_member_name(expr->left);
212 if (!member)
213 return;
214 get_absolute_rl(expr->right, &rl);
215 add_global_type_val(member, rl);
216 free_string(member);
219 static void unop_expr(struct expression *expr)
221 struct range_list *rl;
222 char *member;
224 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
225 return;
227 expr = strip_expr(expr->unop);
228 member = get_member_name(expr);
229 if (!member)
230 return;
231 rl = alloc_whole_rl(get_type(expr));
232 add_type_val(member, rl);
233 free_string(member);
236 static void asm_expr(struct statement *stmt)
238 struct expression *expr;
239 struct range_list *rl;
240 char *member;
241 int state = 0;
243 FOR_EACH_PTR(stmt->asm_outputs, expr) {
244 switch (state) {
245 case 0: /* identifier */
246 case 1: /* constraint */
247 state++;
248 continue;
249 case 2: /* expression */
250 state = 0;
251 member = get_member_name(expr);
252 if (!member)
253 continue;
254 rl = alloc_whole_rl(get_type(expr));
255 add_type_val(member, rl);
256 free_string(member);
257 continue;
259 } END_FOR_EACH_PTR(expr);
262 static void db_param_add(struct expression *expr, int param, char *key, char *value)
264 struct expression *arg;
265 struct symbol *type;
266 struct range_list *rl;
267 char *member;
269 if (strcmp(key, "*$$") != 0)
270 return;
272 while (expr->type == EXPR_ASSIGNMENT)
273 expr = strip_expr(expr->right);
274 if (expr->type != EXPR_CALL)
275 return;
277 arg = get_argument_from_call_expr(expr->args, param);
278 arg = strip_expr(arg);
279 if (!arg)
280 return;
281 type = get_member_type_from_key(arg, key);
282 if (arg->type != EXPR_PREOP || arg->op != '&')
283 return;
284 arg = strip_expr(arg->unop);
286 member = get_member_name(arg);
287 if (!member)
288 return;
289 call_results_to_rl(expr, type, value, &rl);
290 add_type_val(member, rl);
291 free_string(member);
294 static void match_end_func_info(struct symbol *sym)
296 struct sm_state *sm;
298 FOR_EACH_PTR(fn_type_val, sm) {
299 sql_insert_function_type_value(sm->name, sm->state->name);
300 } END_FOR_EACH_PTR(sm);
302 free_slist(&fn_type_val);
305 static void match_end_file(struct symbol_list *sym_list)
307 struct sm_state *sm;
309 FOR_EACH_PTR(global_type_val, sm) {
310 sql_insert_function_type_value(sm->name, sm->state->name);
311 } END_FOR_EACH_PTR(sm);
314 void register_type_val(int id)
316 if (!option_info)
317 return;
319 my_id = id;
321 add_hook(&match_assign_value, ASSIGNMENT_HOOK);
322 add_hook(&match_assign_pointer, ASSIGNMENT_HOOK);
323 add_hook(&unop_expr, OP_HOOK);
324 add_hook(&asm_expr, ASM_HOOK);
325 select_return_states_hook(ADDED_VALUE, &db_param_add);
327 add_hook(&match_inline_start, INLINE_FN_START);
328 add_hook(&match_inline_end, INLINE_FN_END);
330 add_hook(&match_end_func_info, END_FUNC_HOOK);
332 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
333 add_hook(&match_end_file, END_FILE_HOOK);