constraints: fix selecting the required constraint
[smatch.git] / smatch_parse_call_math.c
blob1512bdb1e5c4431268bbadf97f62b1779af69399
1 /*
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
18 #include "smatch.h"
19 #include "smatch_slist.h"
20 #include "smatch_extra.h"
22 static int my_id;
24 struct {
25 const char *func;
26 int param;
27 } alloc_functions[] = {
28 {"kmalloc", 0},
29 {"__kmalloc", 0},
30 {"vmalloc", 0},
31 {"__vmalloc", 0},
32 {"__vmalloc_node", 0},
35 static struct range_list_stack *rl_stack;
36 static struct string_list *op_list;
38 static void push_op(char c)
40 char *p;
42 p = malloc(1);
43 p[0] = c;
44 add_ptr_list(&op_list, p);
47 static char pop_op(void)
49 char *p;
50 char c;
52 if (!op_list) {
53 sm_msg("internal smatch error %s", __func__);
54 return '\0';
57 p = last_ptr_list((struct ptr_list *)op_list);
59 delete_ptr_list_last((struct ptr_list **)&op_list);
60 c = p[0];
61 free(p);
63 return c;
66 static int op_precedence(char c)
68 switch (c) {
69 case '+':
70 case '-':
71 return 1;
72 case '*':
73 case '/':
74 return 2;
75 default:
76 return 0;
80 static int top_op_precedence(void)
82 char *p;
84 if (!op_list)
85 return 0;
87 p = last_ptr_list((struct ptr_list *)op_list);
88 return op_precedence(p[0]);
91 static void rl_pop_until(char c)
93 char op;
94 struct range_list *left, *right;
95 struct range_list *res;
97 while (top_op_precedence() && op_precedence(c) <= top_op_precedence()) {
98 op = pop_op();
99 right = pop_rl(&rl_stack);
100 left = pop_rl(&rl_stack);
101 res = rl_binop(left, op, right);
102 if (!res)
103 res = alloc_whole_rl(&llong_ctype);
104 push_rl(&rl_stack, res);
108 static void rl_discard_stacks(void)
110 while (op_list)
111 pop_op();
112 while (rl_stack)
113 pop_rl(&rl_stack);
116 static int read_rl_from_var(struct expression *call, char *p, char **end, struct range_list **rl)
118 struct expression *arg;
119 struct smatch_state *state;
120 long param;
121 char *name;
122 struct symbol *sym;
123 char buf[256];
124 int star;
126 p++;
127 param = strtol(p, &p, 10);
129 arg = get_argument_from_call_expr(call->args, param);
130 if (!arg)
131 return 0;
133 if (*p != '-' && *p != '.') {
134 get_absolute_rl(arg, rl);
135 *end = p;
136 return 1;
139 *end = strchr(p, ' ');
141 if (arg->type == EXPR_PREOP && arg->op == '&') {
142 arg = strip_expr(arg->unop);
143 star = 0;
144 p++;
145 } else {
146 star = 1;
147 p += 2;
150 name = expr_to_var_sym(arg, &sym);
151 if (!name)
152 return 0;
153 snprintf(buf, sizeof(buf), "%s%s", name, star ? "->" : ".");
154 free_string(name);
156 if (*end - p + strlen(buf) >= sizeof(buf))
157 return 0;
158 strncat(buf, p, *end - p);
160 state = get_state(SMATCH_EXTRA, buf, sym);
161 if (!state)
162 return 0;
163 *rl = estate_rl(state);
164 return 1;
167 static int read_var_num(struct expression *call, char *p, char **end, struct range_list **rl)
169 sval_t sval;
171 while (*p == ' ')
172 p++;
174 if (*p == '$')
175 return read_rl_from_var(call, p, end, rl);
177 sval.type = &llong_ctype;
178 sval.value = strtoll(p, end, 10);
179 if (*end == p)
180 return 0;
181 *rl = alloc_rl(sval, sval);
182 return 1;
185 static char *read_op(char *p)
187 while (*p == ' ')
188 p++;
190 switch (*p) {
191 case '+':
192 case '-':
193 case '*':
194 case '/':
195 return p;
196 default:
197 return NULL;
201 int parse_call_math_rl(struct expression *call, char *math, struct range_list **rl)
203 struct range_list *tmp;
204 char *c;
206 /* try to implement shunting yard algorithm. */
208 c = (char *)math;
209 while (1) {
210 if (option_debug)
211 sm_msg("parsing %s", c);
213 /* read a number and push it onto the number stack */
214 if (!read_var_num(call, c, &c, &tmp))
215 goto fail;
216 push_rl(&rl_stack, tmp);
218 if (option_debug)
219 sm_msg("val = %s remaining = %s", show_rl(tmp), c);
221 if (!*c)
222 break;
223 if (*c == ']' && *(c + 1) == '\0')
224 break;
226 c = read_op(c);
227 if (!c)
228 goto fail;
230 if (option_debug)
231 sm_msg("op = %c remaining = %s", *c, c);
233 rl_pop_until(*c);
234 push_op(*c);
235 c++;
238 rl_pop_until(0);
239 *rl = pop_rl(&rl_stack);
240 return 1;
241 fail:
242 rl_discard_stacks();
243 return 0;
246 int parse_call_math(struct expression *call, char *math, sval_t *sval)
248 struct range_list *rl;
250 if (!parse_call_math_rl(call, math, &rl))
251 return 0;
252 if (!rl_to_sval(rl, sval))
253 return 0;
254 return 1;
257 static struct smatch_state *alloc_state_sname(char *sname)
259 struct smatch_state *state;
261 state = __alloc_smatch_state(0);
262 state->name = sname;
263 state->data = INT_PTR(1);
264 return state;
267 static int get_arg_number(struct expression *expr)
269 struct symbol *sym;
270 struct symbol *arg;
271 int i;
273 expr = strip_expr(expr);
274 if (expr->type != EXPR_SYMBOL)
275 return -1;
276 sym = expr->symbol;
278 i = 0;
279 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
280 if (arg == sym)
281 return i;
282 i++;
283 } END_FOR_EACH_PTR(arg);
285 return -1;
288 static int format_name_sym_helper(char *buf, int remaining, char *name, struct symbol *sym)
290 int ret = 0;
291 int arg;
292 char *param_name;
293 int name_len;
295 if (!name || !sym || !sym->ident)
296 goto free;
297 arg = get_param_num_from_sym(sym);
298 if (arg < 0)
299 goto free;
300 if (param_was_set_var_sym(name, sym))
301 goto free;
303 param_name = sym->ident->name;
304 name_len = strlen(param_name);
306 if (name[name_len] == '\0')
307 ret = snprintf(buf, remaining, "$%d", arg);
308 else if (name[name_len] == '-')
309 ret = snprintf(buf, remaining, "$%d%s", arg, name + name_len);
310 else
311 goto free;
313 remaining -= ret;
314 if (remaining <= 0)
315 ret = 0;
317 free:
318 free_string(name);
320 return ret;
324 static int format_variable_helper(char *buf, int remaining, struct expression *expr)
326 char *name;
327 struct symbol *sym;
329 name = expr_to_var_sym(expr, &sym);
330 return format_name_sym_helper(buf, remaining, name, sym);
333 static int format_call_to_param_mapping(char *buf, int remaining, struct expression *expr)
335 char *name;
336 struct symbol *sym;
338 name = map_call_to_param_name_sym(expr, &sym);
339 return format_name_sym_helper(buf, remaining, name, sym);
342 static int format_expr_helper(char *buf, int remaining, struct expression *expr)
344 sval_t sval;
345 int ret;
346 char *cur;
348 if (!expr)
349 return 0;
351 cur = buf;
353 if (expr->type == EXPR_BINOP) {
354 ret = format_expr_helper(cur, remaining, expr->left);
355 if (ret == 0)
356 return 0;
357 remaining -= ret;
358 if (remaining <= 0)
359 return 0;
360 cur += ret;
362 ret = snprintf(cur, remaining, " %s ", show_special(expr->op));
363 remaining -= ret;
364 if (remaining <= 0)
365 return 0;
366 cur += ret;
368 ret = format_expr_helper(cur, remaining, expr->right);
369 if (ret == 0)
370 return 0;
371 remaining -= ret;
372 if (remaining <= 0)
373 return 0;
374 cur += ret;
375 return cur - buf;
378 if (get_implied_value(expr, &sval)) {
379 ret = snprintf(cur, remaining, "%s", sval_to_str(sval));
380 remaining -= ret;
381 if (remaining <= 0)
382 return 0;
383 return ret;
386 if (expr->type == EXPR_CALL)
387 return format_call_to_param_mapping(cur, remaining, expr);
389 return format_variable_helper(cur, remaining, expr);
392 static char *format_expr(struct expression *expr)
394 char buf[256];
395 int ret;
397 ret = format_expr_helper(buf, sizeof(buf), expr);
398 if (ret == 0)
399 return NULL;
401 return alloc_sname(buf);
404 char *get_value_in_terms_of_parameter_math(struct expression *expr)
406 struct expression *tmp;
407 char buf[256];
408 sval_t dummy;
409 int ret;
411 tmp = get_assigned_expr(expr);
412 if (tmp)
413 expr = tmp;
415 if (get_implied_value(expr, &dummy))
416 return NULL;
418 ret = format_expr_helper(buf, sizeof(buf), expr);
419 if (ret == 0)
420 return NULL;
422 return alloc_sname(buf);
425 char *get_value_in_terms_of_parameter_math_var_sym(const char *name, struct symbol *sym)
427 struct expression *expr;
428 char buf[256];
429 int ret;
431 expr = get_assigned_expr_name_sym(name, sym);
432 if (!expr)
433 return NULL;
435 ret = format_expr_helper(buf, sizeof(buf), expr);
436 if (ret == 0)
437 return NULL;
439 return alloc_sname(buf);
443 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
445 int size_arg = PTR_INT(_size_arg);
446 struct expression *right;
447 struct expression *size_expr;
448 char *sname;
450 right = strip_expr(expr->right);
451 size_expr = get_argument_from_call_expr(right->args, size_arg);
453 sname = format_expr(size_expr);
454 if (!sname)
455 return;
456 set_state_expr(my_id, expr->left, alloc_state_sname(sname));
459 static char *swap_format(struct expression *call, char *format)
461 char buf[256];
462 sval_t sval;
463 long param;
464 struct expression *arg;
465 char *p;
466 char *out;
467 int ret;
469 if (format[0] == '$' && format[2] == '\0') {
470 param = strtol(format + 1, NULL, 10);
471 arg = get_argument_from_call_expr(call->args, param);
472 if (!arg)
473 return NULL;
474 return format_expr(arg);
477 buf[0] = '\0';
478 p = format;
479 out = buf;
480 while (*p) {
481 if (*p == '$') {
482 p++;
483 param = strtol(p, &p, 10);
484 arg = get_argument_from_call_expr(call->args, param);
485 if (!arg)
486 return NULL;
487 param = get_arg_number(arg);
488 if (param >= 0) {
489 ret = snprintf(out, buf + sizeof(buf) - out, "$%ld", param);
490 out += ret;
491 if (out >= buf + sizeof(buf))
492 return NULL;
493 } else if (get_implied_value(arg, &sval)) {
494 ret = snprintf(out, buf + sizeof(buf) - out, "%s", sval_to_str(sval));
495 out += ret;
496 if (out >= buf + sizeof(buf))
497 return NULL;
498 } else {
499 return NULL;
502 *out = *p;
503 p++;
504 out++;
506 if (buf[0] == '\0')
507 return NULL;
508 *out = '\0';
509 return alloc_sname(buf);
512 static char *buf_size_recipe;
513 static int db_buf_size_callback(void *unused, int argc, char **argv, char **azColName)
515 if (argc != 1)
516 return 0;
518 if (!buf_size_recipe)
519 buf_size_recipe = alloc_sname(argv[0]);
520 else if (strcmp(buf_size_recipe, argv[0]) != 0)
521 buf_size_recipe = alloc_sname("invalid");
522 return 0;
525 static char *get_allocation_recipe_from_call(struct expression *expr)
527 struct symbol *sym;
528 static char sql_filter[1024];
529 int i;
531 if (is_fake_call(expr))
532 return NULL;
533 expr = strip_expr(expr);
534 if (expr->fn->type != EXPR_SYMBOL)
535 return NULL;
536 sym = expr->fn->symbol;
537 if (!sym)
538 return NULL;
540 for (i = 0; i < ARRAY_SIZE(alloc_functions); i++) {
541 if (strcmp(sym->ident->name, alloc_functions[i].func) == 0) {
542 char buf[32];
544 snprintf(buf, sizeof(buf), "$%d", alloc_functions[i].param);
545 buf_size_recipe = alloc_sname(buf);
546 return swap_format(expr, buf_size_recipe);
550 if (sym->ctype.modifiers & MOD_STATIC) {
551 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
552 get_filename(), sym->ident->name);
553 } else {
554 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
555 sym->ident->name);
558 buf_size_recipe = NULL;
559 run_sql(db_buf_size_callback, NULL,
560 "select value from return_states where type=%d and %s",
561 BUF_SIZE, sql_filter);
562 if (!buf_size_recipe || strcmp(buf_size_recipe, "invalid") == 0)
563 return NULL;
564 return swap_format(expr, buf_size_recipe);
567 static void match_call_assignment(struct expression *expr)
569 char *sname;
571 sname = get_allocation_recipe_from_call(expr->right);
572 if (!sname)
573 return;
574 set_state_expr(my_id, expr->left, alloc_state_sname(sname));
577 static void match_returns_call(int return_id, char *return_ranges, struct expression *call)
579 char *sname;
581 sname = get_allocation_recipe_from_call(call);
582 if (option_debug)
583 sm_msg("sname = %s", sname);
584 if (!sname)
585 return;
587 sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "",
588 sname);
591 static void print_returned_allocations(int return_id, char *return_ranges, struct expression *expr)
593 struct smatch_state *state;
594 struct symbol *sym;
595 char *name;
597 expr = strip_expr(expr);
598 if (!expr)
599 return;
601 if (expr->type == EXPR_CALL) {
602 match_returns_call(return_id, return_ranges, expr);
603 return;
606 name = expr_to_var_sym(expr, &sym);
607 if (!name || !sym)
608 goto free;
610 state = get_state(my_id, name, sym);
611 if (!state || !state->data)
612 goto free;
614 sql_insert_return_states(return_id, return_ranges, BUF_SIZE, -1, "",
615 state->name);
616 free:
617 free_string(name);
620 void register_parse_call_math(int id)
622 int i;
624 my_id = id;
626 for (i = 0; i < ARRAY_SIZE(alloc_functions); i++)
627 add_function_assign_hook(alloc_functions[i].func, &match_alloc,
628 INT_PTR(alloc_functions[i].param));
629 add_hook(&match_call_assignment, CALL_ASSIGNMENT_HOOK);
630 add_split_return_callback(print_returned_allocations);