math: calculating the sizeof() used to modify the expression
[smatch.git] / smatch_parse_call_math.c
blob59fe1cc068e5fa81c030bac897730a859570d6a5
1 /*
2 * smatch/smatch_parse_call_math.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_slist.h"
12 #include "smatch_extra.h"
14 static int my_id;
16 struct {
17 const char *func;
18 int param;
19 } alloc_functions[] = {
20 {"kmalloc", 0},
21 {"__kmalloc", 0},
22 {"vmalloc", 0},
23 {"__vmalloc", 0},
24 {"__vmalloc_node", 0},
27 DECLARE_PTR_LIST(sval_list, sval_t);
29 static struct sval_list *num_list;
30 static struct string_list *op_list;
32 static void push_val(sval_t sval)
34 sval_t *p;
36 p = malloc(sizeof(*p));
37 *p = sval;
38 add_ptr_list(&num_list, p);
41 static sval_t pop_val()
43 sval_t *p;
44 sval_t ret;
46 if (!num_list) {
47 sm_msg("internal bug: %s popping empty list", __func__);
48 ret.type = &llong_ctype;
49 ret.value = 0;
50 return ret;
52 p = last_ptr_list((struct ptr_list *)num_list);
53 delete_ptr_list_last((struct ptr_list **)&num_list);
54 ret = *p;
55 free(p);
57 return ret;
60 static void push_op(char c)
62 char *p;
64 p = malloc(1);
65 p[0] = c;
66 add_ptr_list(&op_list, p);
69 static char pop_op()
71 char *p;
72 char c;
74 if (!op_list) {
75 sm_msg("internal smatch error %s", __func__);
76 return '\0';
79 p = last_ptr_list((struct ptr_list *)op_list);
81 delete_ptr_list_last((struct ptr_list **)&op_list);
82 c = p[0];
83 free(p);
85 return c;
88 static int op_precedence(char c)
90 switch (c) {
91 case '+':
92 case '-':
93 return 1;
94 case '*':
95 case '/':
96 return 2;
97 default:
98 return 0;
102 static int top_op_precedence()
104 char *p;
106 if (!op_list)
107 return 0;
109 p = last_ptr_list((struct ptr_list *)op_list);
110 return op_precedence(p[0]);
113 static void pop_until(char c)
115 char op;
116 sval_t left, right;
117 sval_t res;
119 while (top_op_precedence() && op_precedence(c) <= top_op_precedence()) {
120 op = pop_op();
121 right = pop_val();
122 left = pop_val();
123 res = sval_binop(left, op, right);
124 push_val(res);
128 static int get_implied_param(struct expression *call, int param, sval_t *sval)
130 struct expression *arg;
132 arg = get_argument_from_call_expr(call->args, param);
133 return get_implied_value(arg, sval);
136 static int read_number(struct expression *call, char *p, char **end, sval_t *sval)
138 long param;
140 while (*p == ' ')
141 p++;
143 if (*p == '<') {
144 p++;
145 param = strtol(p, &p, 10);
146 if (!get_implied_param(call, param, sval))
147 return 0;
148 *end = p + 1;
149 } else {
150 sval->type = &llong_ctype;
151 sval->value = strtoll(p, end, 10);
152 if (*end == p)
153 return 0;
155 return 1;
158 static char *read_op(char *p)
160 while (*p == ' ')
161 p++;
163 switch (*p) {
164 case '+':
165 case '-':
166 case '*':
167 case '/':
168 return p;
169 default:
170 return NULL;
174 int parse_call_math(struct expression *call, char *math, sval_t *sval)
176 sval_t tmp;
177 char *c;
179 /* try to implement shunting yard algorithm. */
181 c = (char *)math;
182 while (1) {
183 if (option_debug)
184 sm_msg("parsing %s", c);
186 /* read a number and push it onto the number stack */
187 if (!read_number(call, c, &c, &tmp))
188 goto fail;
189 push_val(tmp);
191 if (option_debug)
192 sm_msg("val = %s remaining = %s", sval_to_str(tmp), c);
194 if (!*c)
195 break;
197 c = read_op(c);
198 if (!c)
199 goto fail;
201 if (option_debug)
202 sm_msg("op = %c remaining = %s", *c, c);
204 pop_until(*c);
205 push_op(*c);
206 c++;
209 pop_until(0);
210 *sval = pop_val();
211 return 1;
212 fail:
213 pop_until(0); /* discard stack */
214 return 0;
217 static struct smatch_state *alloc_state_sname(char *sname)
219 struct smatch_state *state;
221 state = __alloc_smatch_state(0);
222 state->name = sname;
223 state->data = INT_PTR(1);
224 return state;
227 static int get_arg_number(struct expression *expr)
229 struct symbol *sym;
230 struct symbol *arg;
231 int i;
233 expr = strip_expr(expr);
234 if (expr->type != EXPR_SYMBOL)
235 return -1;
236 sym = expr->symbol;
238 i = 0;
239 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
240 if (arg == sym)
241 return i;
242 i++;
243 } END_FOR_EACH_PTR(arg);
245 return -1;
248 static int format_expr_helper(char *buf, int remaining, struct expression *expr)
250 int arg;
251 sval_t sval;
252 int ret;
253 char *cur;
255 cur = buf;
257 if (expr->type == EXPR_BINOP) {
258 ret = format_expr_helper(cur, remaining, expr->left);
259 if (ret == 0)
260 return 0;
261 remaining -= ret;
262 if (remaining <= 0)
263 return 0;
264 cur += ret;
266 ret = snprintf(cur, remaining, " %s ", show_special(expr->op));
267 remaining -= ret;
268 if (remaining <= 0)
269 return 0;
270 cur += ret;
272 ret = format_expr_helper(cur, remaining, expr->right);
273 if (ret == 0)
274 return 0;
275 remaining -= ret;
276 if (remaining <= 0)
277 return 0;
278 cur += ret;
279 return cur - buf;
282 arg = get_arg_number(expr);
283 if (arg >= 0) {
284 ret = snprintf(cur, remaining, "<%d>", arg);
285 remaining -= ret;
286 if (remaining <= 0)
287 return 0;
288 return ret;
291 if (get_implied_value(expr, &sval)) {
292 ret = snprintf(cur, remaining, "%s", sval_to_str(sval));
293 remaining -= ret;
294 if (remaining <= 0)
295 return 0;
296 return ret;
299 return 0;
302 static char *format_expr(struct expression *expr)
304 char buf[256];
305 int ret;
307 ret = format_expr_helper(buf, sizeof(buf), expr);
308 if (ret == 0)
309 return NULL;
311 return alloc_sname(buf);
314 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
316 int size_arg = PTR_INT(_size_arg);
317 struct expression *right;
318 struct expression *size_expr;
319 char *sname;
321 right = strip_expr(expr->right);
322 size_expr = get_argument_from_call_expr(right->args, size_arg);
324 sname = format_expr(size_expr);
325 if (!sname)
326 return;
327 set_state_expr(my_id, expr->left, alloc_state_sname(sname));
330 static char *swap_format(struct expression *call, char *format)
332 static char buf[256];
333 sval_t sval;
334 long param;
335 struct expression *arg;
336 char *p;
337 char *out;
338 int ret;
340 if (format[0] == '<' && format[2] == '>' && format[3] == '\0') {
341 param = strtol(format + 1, NULL, 10);
342 arg = get_argument_from_call_expr(call->args, param);
343 if (!arg)
344 return NULL;
345 return format_expr(arg);
348 buf[0] = '\0';
349 p = format;
350 out = buf;
351 while (*p) {
352 if (*p == '<') {
353 p++;
354 param = strtol(p, &p, 10);
355 if (*p != '>')
356 return NULL;
357 p++;
358 arg = get_argument_from_call_expr(call->args, param);
359 if (!arg)
360 return NULL;
361 param = get_arg_number(arg);
362 if (param >= 0) {
363 ret = snprintf(out, buf + sizeof(buf) - out, "<%ld>", param);
364 out += ret;
365 if (out >= buf + sizeof(buf))
366 return NULL;
367 } else if (get_implied_value(arg, &sval)) {
368 ret = snprintf(out, buf + sizeof(buf) - out, "%s", sval_to_str(sval));
369 out += ret;
370 if (out >= buf + sizeof(buf))
371 return NULL;
372 } else {
373 return NULL;
376 *out = *p;
377 p++;
378 out++;
380 if (buf[0] == '\0')
381 return NULL;
382 return alloc_sname(buf);
385 static char *buf_size_recipe;
386 static int db_buf_size_callback(void *unused, int argc, char **argv, char **azColName)
388 if (argc != 1)
389 return 0;
391 if (!buf_size_recipe)
392 buf_size_recipe = alloc_sname(argv[0]);
393 else if (strcmp(buf_size_recipe, argv[0]) != 0)
394 buf_size_recipe = alloc_sname("invalid");
395 return 0;
398 static char *get_allocation_recipe_from_call(struct expression *expr)
400 struct symbol *sym;
401 static char sql_filter[1024];
402 int i;
404 expr = strip_expr(expr);
405 if (expr->fn->type != EXPR_SYMBOL)
406 return NULL;
407 sym = expr->fn->symbol;
408 if (!sym)
409 return NULL;
411 for (i = 0; i < ARRAY_SIZE(alloc_functions); i++) {
412 if (strcmp(sym->ident->name, alloc_functions[i].func) == 0) {
413 char buf[32];
415 snprintf(buf, sizeof(buf), "<%d>", alloc_functions[i].param);
416 buf_size_recipe = alloc_sname(buf);
417 return swap_format(expr, buf_size_recipe);
421 if (sym->ctype.modifiers & MOD_STATIC) {
422 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
423 get_filename(), sym->ident->name);
424 } else {
425 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
426 sym->ident->name);
429 buf_size_recipe = NULL;
430 run_sql(db_buf_size_callback, "select value from return_states where type=%d and %s",
431 BUF_SIZE, sql_filter);
432 if (!buf_size_recipe || strcmp(buf_size_recipe, "invalid") == 0)
433 return NULL;
434 return swap_format(expr, buf_size_recipe);
437 static void match_call_assignment(struct expression *expr)
439 char *sname;
441 sname = get_allocation_recipe_from_call(expr->right);
442 if (!sname)
443 return;
444 set_state_expr(my_id, expr->left, alloc_state_sname(sname));
447 static void match_returns_call(int return_id, char *return_ranges, struct expression *call)
449 char *sname;
451 sname = get_allocation_recipe_from_call(call);
452 if (option_debug)
453 sm_msg("sname = %s", sname);
454 if (!sname)
455 return;
456 sm_msg("info: return_allocation %d '%s' '%s' %s",
457 return_id, return_ranges, sname, global_static());
460 static void print_returned_allocations(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist)
462 struct smatch_state *state;
463 struct symbol *sym;
464 char *name;
466 expr = strip_expr(expr);
467 if (!expr)
468 return;
470 if (expr->type == EXPR_CALL) {
471 match_returns_call(return_id, return_ranges, expr);
472 return;
475 name = expr_to_var_sym(expr, &sym);
476 if (!name || !sym)
477 goto free;
479 state = get_state_slist(slist, my_id, name, sym);
480 if (!state || !state->data)
481 goto free;
482 sm_msg("info: return_allocation %d '%s' '%s' %s",
483 return_id, return_ranges, state->name, global_static());
484 free:
485 free_string(name);
488 void register_parse_call_math(int id)
490 int i;
491 if (!option_info)
492 return;
494 my_id = id;
495 for (i = 0; i < ARRAY_SIZE(alloc_functions); i++)
496 add_function_assign_hook(alloc_functions[i].func, &match_alloc,
497 INT_PTR(alloc_functions[i].param));
498 add_hook(&match_call_assignment, CALL_ASSIGNMENT_HOOK);
499 add_returned_state_callback(print_returned_allocations);