comparison: fix how addresses are handled
[smatch.git] / smatch_param_key.c
blobcf148cea4bc11eb5499ddeae797d7c2a231c8da9
1 /*
2 * Copyright (C) 2020 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_extra.h"
20 #include "smatch_slist.h"
22 static int my_id;
24 static void undef(struct sm_state *sm, struct expression *mod_expr)
26 set_state(my_id, sm->name, sm->sym, &undefined);
29 static char *swap_names(const char *orig, const char *remove, const char *add)
31 char buf[64];
32 int offset, len, ret;
33 bool is_addr = false;
35 if (add[0] == '&') {
36 is_addr = true;
37 add++;
40 offset = 0;
41 while(orig[offset] == '*' || orig[offset] == '(')
42 offset++;
44 len = strlen(remove);
45 if (len + offset > strlen(orig))
46 return NULL;
47 if (orig[offset + len] != '-')
48 return NULL;
49 if (strncmp(orig + offset, remove, len) != 0)
50 return NULL;
52 ret = snprintf(buf, sizeof(buf), "%.*s%s%s%s", offset, orig,
53 add, is_addr ? "." : "->", orig + offset + 2 + len);
54 if (ret >= sizeof(buf))
55 return NULL;
56 return alloc_string(buf);
59 static char *swap_with_param(const char *name, struct symbol *sym, struct symbol **sym_p)
61 struct smatch_state *state;
62 struct var_sym *var_sym;
63 char *ret;
66 * Say you know that "foo = bar;" and you have a state "foo->baz" then
67 * we can just substitute "bar" for "foo" giving "bar->baz".
70 if (!sym || !sym->ident)
71 return NULL;
73 state = get_state(my_id, sym->ident->name, sym);
74 if (!state || !state->data)
75 return NULL;
76 var_sym = state->data;
78 ret = swap_names(name, sym->ident->name, var_sym->var);
79 if (!ret)
80 return NULL;
82 *sym_p = var_sym->sym;
83 return ret;
86 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
88 struct symbol *type;
89 char buf[256];
90 char *tmp;
91 bool address = false;
92 int star_cnt = 0;
93 bool add_dot = false;
94 int ret;
96 if (!arg)
97 return NULL;
99 arg = strip_expr(arg);
101 if (strcmp(key, "$") == 0)
102 return expr_to_var_sym(arg, sym);
104 if (strcmp(key, "*$") == 0) {
105 if (arg->type == EXPR_PREOP && arg->op == '&') {
106 arg = strip_expr(arg->unop);
107 return expr_to_var_sym(arg, sym);
108 } else {
109 tmp = expr_to_var_sym(arg, sym);
110 if (!tmp)
111 return NULL;
112 ret = snprintf(buf, sizeof(buf), "*%s", tmp);
113 free_string(tmp);
114 if (ret >= sizeof(buf))
115 return NULL;
116 return alloc_string(buf);
120 if (strncmp(key, "(*$)", 4) == 0) {
121 if (arg->type == EXPR_PREOP && arg->op == '&') {
122 arg = strip_expr(arg->unop);
123 snprintf(buf, sizeof(buf), "$%s", key + 4);
124 return get_variable_from_key(arg, buf, sym);
125 } else {
126 tmp = expr_to_var_sym(arg, sym);
127 if (!tmp)
128 return NULL;
129 ret = snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
130 free_string(tmp);
131 if (ret >= sizeof(buf))
132 return NULL;
133 return alloc_string(buf);
137 while (key[0] == '*') {
138 star_cnt++;
139 key++;
142 if (key[0] == '&') {
143 address = true;
144 key++;
148 * FIXME: This is a hack.
149 * We should be able to parse expressions like (*$)->foo and *$->foo.
151 type = get_type(arg);
152 if (is_struct_ptr(type))
153 add_dot = true;
155 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
156 arg = strip_expr(arg->unop);
157 star_cnt--;
160 if (arg->type == EXPR_PREOP && arg->op == '&') {
161 arg = strip_expr(arg->unop);
162 tmp = expr_to_var_sym(arg, sym);
163 if (!tmp)
164 return NULL;
165 ret = snprintf(buf, sizeof(buf), "%s%.*s%s.%s",
166 address ? "&" : "", star_cnt, "**********",
167 tmp, key + 3);
168 if (ret >= sizeof(buf))
169 return NULL;
170 return alloc_string(buf);
173 tmp = expr_to_var_sym(arg, sym);
174 if (!tmp)
175 return NULL;
176 ret = snprintf(buf, sizeof(buf), "%s%.*s%s%s",
177 address ? "&" : "", star_cnt, "**********", tmp, key + 1);
178 free_string(tmp);
179 if (ret >= sizeof(buf))
180 return NULL;
181 return alloc_string(buf);
184 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
186 *vsl = NULL;
188 if (strcmp("$", key) == 0)
189 return expr_to_chunk_sym_vsl(arg, sym, vsl);
190 return get_variable_from_key(arg, key, sym);
193 static char *state_name_to_param_name(const char *state_name, const char *param_name)
195 bool address = false;
196 int star_cnt = 0;
197 int name_len;
198 char buf[256];
199 int ret;
201 name_len = strlen(param_name);
203 while (state_name[0] == '*') {
204 star_cnt++;
205 state_name++;
208 if (state_name[0] == '&') {
209 address = true;
210 state_name++;
213 /* ten out of ten stars! */
214 if (star_cnt > 10)
215 return NULL;
217 if (strncmp(state_name, "(*", 2) == 0 &&
218 strncmp(state_name + 2, param_name, name_len) == 0 &&
219 state_name[name_len + 2] == ')') {
220 ret = snprintf(buf, sizeof(buf), "%s%.*s(*$)%s",
221 address ? "&" : "",
222 star_cnt, "**********",
223 state_name + name_len + 3);
224 if (ret >= sizeof(buf))
225 return NULL;
226 return alloc_sname(buf);
229 if (strcmp(state_name, param_name) == 0) {
230 snprintf(buf, sizeof(buf), "%s%.*s$",
231 address ? "&" : "",
232 star_cnt, "**********");
233 return alloc_sname(buf);
236 /* check for '-' from "->" */
237 if (strncmp(state_name, param_name, name_len) == 0 &&
238 state_name[name_len] == '-') {
239 ret = snprintf(buf, sizeof(buf), "%s%.*s$%s",
240 address ? "&" : "",
241 star_cnt, "**********",
242 state_name + name_len);
243 if (ret >= sizeof(buf))
244 return NULL;
245 return alloc_sname(buf);
247 return NULL;
250 char *get_param_name_var_sym(const char *name, struct symbol *sym)
252 if (!sym || !sym->ident)
253 return NULL;
255 return state_name_to_param_name(name, sym->ident->name);
258 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
260 struct symbol *type;
261 const char *sym_name;
262 int name_len;
263 static char buf[256];
266 * mtag_name is different from param_name because mtags can be a struct
267 * instead of a struct pointer. But we want to treat it like a pointer
268 * because really an mtag is a pointer. Or in other words, if you pass
269 * a struct foo then you want to talk about foo.bar but with an mtag
270 * you want to refer to it as foo->bar.
274 if (!sym || !sym->ident)
275 return NULL;
277 type = get_real_base_type(sym);
278 if (type && type->type == SYM_BASETYPE)
279 return "*$";
281 sym_name = sym->ident->name;
282 name_len = strlen(sym_name);
284 if (state_name[name_len] == '.' && /* check for '-' from "->" */
285 strncmp(state_name, sym_name, name_len) == 0) {
286 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
287 return buf;
290 return state_name_to_param_name(state_name, sym_name);
293 const char *get_mtag_name_expr(struct expression *expr)
295 char *name;
296 struct symbol *sym;
297 const char *ret = NULL;
299 name = expr_to_var_sym(expr, &sym);
300 if (!name || !sym)
301 goto free;
303 ret = get_mtag_name_var_sym(name, sym);
304 free:
305 free_string(name);
306 return ret;
309 char *get_param_name(struct sm_state *sm)
311 return get_param_name_var_sym(sm->name, sm->sym);
314 char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
316 struct smatch_state *state;
317 struct var_sym *var_sym;
318 int param;
320 *sym_p = NULL;
322 // FIXME was modified...
324 param = get_param_num_from_sym(sym);
325 if (param >= 0) {
326 *sym_p = sym;
327 return alloc_string(name);
330 state = get_state(my_id, name, sym);
331 if (state && state->data) {
332 var_sym = state->data;
333 if (!var_sym)
334 return NULL;
336 *sym_p = var_sym->sym;
337 return alloc_string(var_sym->var);
340 return swap_with_param(name, sym, sym_p);
343 char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
345 struct symbol *sym;
346 const char *ret = NULL;
347 char *name;
349 name = expr_to_var_sym(expr, &sym);
350 if (!name || !sym)
351 goto free;
353 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
354 free:
355 free_string(name);
356 return alloc_string(ret);
359 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
360 struct expression *ret_expr,
361 const char **key)
363 const char *param_name;
364 char *other_name;
365 struct symbol *other_sym;
366 int param;
368 if (key)
369 *key = name;
371 /* straight forward param match */
372 param = get_param_num_from_sym(sym);
373 if (param >= 0) {
374 param_name = get_param_name_var_sym(name, sym);
375 if (param_name) {
376 if (key)
377 *key = param_name;
378 return param;
382 /* it's the return value */
383 if (ret_expr) {
384 struct symbol *ret_sym;
385 char *ret_str;
387 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
388 if (ret_str && ret_sym == sym) {
389 param_name = state_name_to_param_name(name, ret_str);
390 if (param_name) {
391 free_string(ret_str);
392 if (key)
393 *key = param_name;
394 return -1;
397 free_string(ret_str);
400 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
401 if (!other_name || !other_sym)
402 return -2;
403 param = get_param_num_from_sym(other_sym);
404 if (param < 0) {
405 sm_msg("internal: '%s' parameter not found", other_name);
406 return -2;
409 param_name = get_param_name_var_sym(other_name, other_sym);
410 if (param_name) {
411 if (key)
412 *key = param_name;
413 return param;
415 return -2;
418 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
419 const char **key)
421 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
424 int map_to_param(const char *name, struct symbol *sym)
426 return get_param_key_from_var_sym(name, sym, NULL, NULL);
429 int get_param_num_from_sym(struct symbol *sym)
431 struct symbol *tmp;
432 int i;
434 if (!sym)
435 return UNKNOWN_SCOPE;
437 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
438 if (sym->ctype.modifiers & MOD_STATIC)
439 return FILE_SCOPE;
440 return GLOBAL_SCOPE;
443 if (!cur_func_sym) {
444 if (!parse_error) {
445 sm_msg("warn: internal. problem with scope: %s",
446 sym->ident ? sym->ident->name : "<anon var>");
448 return GLOBAL_SCOPE;
452 i = 0;
453 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
454 if (tmp == sym)
455 return i;
456 i++;
457 } END_FOR_EACH_PTR(tmp);
458 return LOCAL_SCOPE;
461 int get_param_num(struct expression *expr)
463 struct symbol *sym;
464 char *name;
466 if (!cur_func_sym)
467 return UNKNOWN_SCOPE;
468 name = expr_to_var_sym(expr, &sym);
469 free_string(name);
470 if (!sym)
471 return UNKNOWN_SCOPE;
472 return get_param_num_from_sym(sym);
475 struct symbol *get_param_sym_from_num(int num)
477 struct symbol *sym;
478 int i;
480 if (!cur_func_sym)
481 return NULL;
483 i = 0;
484 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
485 if (i++ == num)
486 return sym;
487 } END_FOR_EACH_PTR(sym);
488 return NULL;
491 char *get_name_sym_from_key(struct expression *expr, int param, const char *key, struct symbol **sym)
493 struct expression *call, *arg;
494 char *name;
496 if (sym)
497 *sym = NULL;
499 if (!expr) {
500 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
501 return NULL;
504 call = expr;
505 while (call->type == EXPR_ASSIGNMENT)
506 call = strip_expr(call->right);
508 if (call->type != EXPR_CALL)
509 return NULL;
511 if (param == -1 &&
512 expr->type == EXPR_ASSIGNMENT &&
513 expr->op == '=') {
514 name = get_variable_from_key(expr->left, key, sym);
515 if (!name || (sym && !*sym))
516 goto free;
517 } else if (param >= 0) {
518 arg = get_argument_from_call_expr(call->args, param);
519 if (!arg)
520 return NULL;
522 name = get_variable_from_key(arg, key, sym);
523 if (!name || (sym && !*sym))
524 goto free;
525 } else {
526 name = alloc_string(key);
529 return name;
530 free:
531 free_string(name);
532 return NULL;
535 static void match_assign(struct expression *expr)
537 struct symbol *param_sym;
538 char *param_name;
540 if (expr->op != '=')
541 return;
543 /* __in_fake_parameter_assign is included deliberately */
544 if (is_fake_call(expr->right) ||
545 __in_fake_struct_assign)
546 return;
548 param_name = get_param_name_sym(expr->right, &param_sym);
549 if (!param_name || !param_sym)
550 goto free;
552 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
553 free:
554 free_string(param_name);
557 void register_param_key(int id)
559 my_id = id;
561 set_dynamic_states(my_id);
562 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
563 add_modification_hook(my_id, &undef);