validation: delete obsolete dev_hold() check
[smatch.git] / smatch_param_key.c
blobe7becb518044220f0340292e32c63670c85ac99a
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 "ctype.h"
19 #include "smatch.h"
20 #include "smatch_extra.h"
21 #include "smatch_slist.h"
23 static int my_id;
25 static void undef(struct sm_state *sm, struct expression *mod_expr)
27 set_state(my_id, sm->name, sm->sym, &undefined);
30 char *swap_names(const char *orig, const char *remove, const char *add)
32 char buf[64];
33 int offset, len, ret;
34 bool is_addr = false;
36 if (add[0] == '&') {
37 is_addr = true;
38 add++;
41 offset = 0;
42 while(orig[offset] == '*' || orig[offset] == '&' || orig[offset] == '(')
43 offset++;
45 len = strlen(remove);
46 if (len + offset > strlen(orig))
47 return NULL;
48 if (orig[offset + len] != '-')
49 return NULL;
50 if (strncmp(orig + offset, remove, len) != 0)
51 return NULL;
53 ret = snprintf(buf, sizeof(buf), "%.*s%s%s%s", offset, orig,
54 add, is_addr ? "." : "->", orig + offset + 2 + len);
55 if (ret >= sizeof(buf))
56 return NULL;
57 return alloc_string(buf);
60 static char *swap_with_param(const char *name, struct symbol *sym, struct symbol **sym_p)
62 struct smatch_state *state;
63 struct var_sym *var_sym;
64 char *ret;
67 * Say you know that "foo = bar;" and you have a state "foo->baz" then
68 * we can just substitute "bar" for "foo" giving "bar->baz".
71 if (!sym || !sym->ident)
72 return NULL;
74 state = get_state(my_id, sym->ident->name, sym);
75 if (!state || !state->data)
76 return NULL;
77 var_sym = state->data;
79 ret = swap_names(name, sym->ident->name, var_sym->var);
80 if (!ret)
81 return NULL;
83 *sym_p = var_sym->sym;
84 return ret;
87 struct expression *map_container_of_to_simpler_expr_key(struct expression *expr, const char *orig_key, char **new_key)
89 int offset;
90 char *p = (char *)orig_key;
91 char *start, *end;
92 char buf[64];
93 int ret;
95 expr = strip_expr(expr);
96 if (expr->type != EXPR_DEREF)
97 return NULL;
99 while (*p != '\0') {
100 if (*p == '(' && isdigit(*(p + 1))) {
101 start = p;
102 offset = strtoul(p + 1, &p, 10);
103 if (!p || p[0] != '<' || p[1] != '~' || p[2] != '$' ||
104 p[3] != ')' || p[4] != '-' || p[5] != '>')
105 return NULL;
106 end = p + 6;
107 break;
109 p++;
111 if (*p == '\0')
112 return NULL;
114 if (offset != get_member_offset_from_deref(expr))
115 return NULL;
117 ret = snprintf(buf, sizeof(buf), "%.*s$.%s", (int)(start - orig_key), orig_key, end);
118 if (ret >= sizeof(buf))
119 return NULL;
120 *new_key = alloc_sname(buf);
121 return expr->deref;
124 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
126 struct symbol *type;
127 char buf[256];
128 char *tmp;
129 bool address = false;
130 int star_cnt = 0;
131 bool add_dot = false;
132 int ret;
134 // FIXME: this function has been marked for deletion!
135 // get_name_sym_from_key()
137 if (!arg)
138 return NULL;
140 arg = strip_expr(arg);
142 if (strcmp(key, "$") == 0)
143 return expr_to_var_sym(arg, sym);
145 if (strcmp(key, "*$") == 0) {
146 if (arg->type == EXPR_PREOP && arg->op == '&') {
147 arg = strip_expr(arg->unop);
148 return expr_to_var_sym(arg, sym);
149 } else {
150 tmp = expr_to_var_sym(arg, sym);
151 if (!tmp)
152 return NULL;
153 ret = snprintf(buf, sizeof(buf), "*%s", tmp);
154 free_string(tmp);
155 if (ret >= sizeof(buf))
156 return NULL;
157 return alloc_string(buf);
161 if (strncmp(key, "(*$)", 4) == 0) {
162 if (arg->type == EXPR_PREOP && arg->op == '&') {
163 arg = strip_expr(arg->unop);
164 snprintf(buf, sizeof(buf), "$%s", key + 4);
165 return get_variable_from_key(arg, buf, sym);
166 } else {
167 tmp = expr_to_var_sym(arg, sym);
168 if (!tmp)
169 return NULL;
170 ret = snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
171 free_string(tmp);
172 if (ret >= sizeof(buf))
173 return NULL;
174 return alloc_string(buf);
178 if (strstr(key, "<~$")) {
179 struct expression *expr;
180 char *new_key;
182 expr = map_container_of_to_simpler_expr_key(arg, key, &new_key);
183 if (!expr)
184 return NULL;
185 arg = expr;
186 key = new_key;
189 while (key[0] == '*') {
190 star_cnt++;
191 key++;
194 if (key[0] == '&') {
195 address = true;
196 key++;
200 * FIXME: This is a hack.
201 * We should be able to parse expressions like (*$)->foo and *$->foo.
203 type = get_type(arg);
204 if (is_struct_ptr(type))
205 add_dot = true;
207 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
208 arg = strip_expr(arg->unop);
209 star_cnt--;
212 if (arg->type == EXPR_PREOP && arg->op == '&') {
213 arg = strip_expr(arg->unop);
214 tmp = expr_to_var_sym(arg, sym);
215 if (!tmp)
216 return NULL;
217 ret = snprintf(buf, sizeof(buf), "%s%.*s%s.%s",
218 address ? "&" : "", star_cnt, "**********",
219 tmp, key + 3);
220 if (ret >= sizeof(buf))
221 return NULL;
222 return alloc_string(buf);
225 tmp = expr_to_var_sym(arg, sym);
226 if (!tmp)
227 return NULL;
228 ret = snprintf(buf, sizeof(buf), "%s%.*s%s%s",
229 address ? "&" : "", star_cnt, "**********", tmp, key + 1);
230 free_string(tmp);
231 if (ret >= sizeof(buf))
232 return NULL;
233 return alloc_string(buf);
236 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
238 *vsl = NULL;
240 if (strcmp("$", key) == 0)
241 return expr_to_chunk_sym_vsl(arg, sym, vsl);
242 return get_variable_from_key(arg, key, sym);
245 static char *state_name_to_param_name(const char *state_name, const char *param_name)
247 bool address = false;
248 int star_cnt = 0;
249 int name_len;
250 char buf[256];
251 int ret;
254 * Normally what happens is that we map "*foo->bar" to "*param->bar"
255 * but with container_of() there is no notation for that in C and it's
256 * just a Smatch invention. So in that case, the state name is the
257 * param name.
259 if (strstr(state_name, "<~$"))
260 return (char *)state_name;
262 name_len = strlen(param_name);
264 while (state_name[0] == '*') {
265 star_cnt++;
266 state_name++;
269 if (state_name[0] == '&') {
270 address = true;
271 state_name++;
274 /* ten out of ten stars! */
275 if (star_cnt > 10)
276 return NULL;
278 if (strncmp(state_name, "(*", 2) == 0 &&
279 strncmp(state_name + 2, param_name, name_len) == 0 &&
280 state_name[name_len + 2] == ')') {
281 ret = snprintf(buf, sizeof(buf), "%s%.*s(*$)%s",
282 address ? "&" : "",
283 star_cnt, "**********",
284 state_name + name_len + 3);
285 if (ret >= sizeof(buf))
286 return NULL;
287 return alloc_sname(buf);
290 if (strcmp(state_name, param_name) == 0) {
291 snprintf(buf, sizeof(buf), "%s%.*s$",
292 address ? "&" : "",
293 star_cnt, "**********");
294 return alloc_sname(buf);
297 /* check for '-' from "->" */
298 if (strncmp(state_name, param_name, name_len) == 0 &&
299 state_name[name_len] == '-') {
300 ret = snprintf(buf, sizeof(buf), "%s%.*s$%s",
301 address ? "&" : "",
302 star_cnt, "**********",
303 state_name + name_len);
304 if (ret >= sizeof(buf))
305 return NULL;
306 return alloc_sname(buf);
308 return NULL;
311 char *get_param_name_var_sym(const char *name, struct symbol *sym)
313 if (!sym || !sym->ident)
314 return NULL;
316 return state_name_to_param_name(name, sym->ident->name);
319 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
321 struct symbol *type;
322 const char *sym_name;
323 int name_len;
324 static char buf[256];
327 * mtag_name is different from param_name because mtags can be a struct
328 * instead of a struct pointer. But we want to treat it like a pointer
329 * because really an mtag is a pointer. Or in other words, if you pass
330 * a struct foo then you want to talk about foo.bar but with an mtag
331 * you want to refer to it as foo->bar.
335 if (!sym || !sym->ident)
336 return NULL;
338 type = get_real_base_type(sym);
339 if (type && type->type == SYM_BASETYPE)
340 return "*$";
342 sym_name = sym->ident->name;
343 name_len = strlen(sym_name);
345 if (state_name[name_len] == '.' && /* check for '-' from "->" */
346 strncmp(state_name, sym_name, name_len) == 0) {
347 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
348 return buf;
351 return state_name_to_param_name(state_name, sym_name);
354 const char *get_mtag_name_expr(struct expression *expr)
356 char *name;
357 struct symbol *sym;
358 const char *ret = NULL;
360 name = expr_to_var_sym(expr, &sym);
361 if (!name || !sym)
362 goto free;
364 ret = get_mtag_name_var_sym(name, sym);
365 free:
366 free_string(name);
367 return ret;
370 char *get_param_name(struct sm_state *sm)
372 return get_param_name_var_sym(sm->name, sm->sym);
375 char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
377 struct smatch_state *state;
378 struct var_sym *var_sym;
379 int param;
381 *sym_p = NULL;
383 // FIXME was modified...
385 param = get_param_num_from_sym(sym);
386 if (param >= 0) {
387 *sym_p = sym;
388 return alloc_string(name);
391 state = get_state(my_id, name, sym);
392 if (state && state->data) {
393 var_sym = state->data;
394 if (!var_sym)
395 return NULL;
397 *sym_p = var_sym->sym;
398 return alloc_string(var_sym->var);
401 /* One would think that handling container_of() should be done here
402 * but it it's quite tricky because we only have a name and a sym
403 * and none of the assignments have been handled yet, either here or
404 * in smatch_assignments.c. On the other hand handling container_of()
405 * in the assignment hook has the advantage that it saves resources and
406 * it should work fine because of the fake assignments which we do.
409 return swap_with_param(name, sym, sym_p);
412 char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
414 struct symbol *sym;
415 const char *ret = NULL;
416 char *name;
418 name = expr_to_var_sym(expr, &sym);
419 if (!name || !sym)
420 goto free;
422 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
423 free:
424 free_string(name);
425 return alloc_string(ret);
428 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
429 struct expression *ret_expr,
430 const char **key)
432 const char *param_name;
433 char *other_name;
434 struct symbol *other_sym;
435 int param;
437 if (key)
438 *key = name;
440 /* straight forward param match */
441 param = get_param_num_from_sym(sym);
442 if (param >= 0) {
443 param_name = get_param_name_var_sym(name, sym);
444 if (param_name) {
445 if (key)
446 *key = param_name;
447 return param;
451 /* it's the return value */
452 if (ret_expr) {
453 struct symbol *ret_sym;
454 char *ret_str;
456 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
457 if (ret_str && ret_sym == sym) {
458 param_name = state_name_to_param_name(name, ret_str);
459 if (param_name) {
460 free_string(ret_str);
461 if (key)
462 *key = param_name;
463 return -1;
466 free_string(ret_str);
469 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
470 if (!other_name || !other_sym)
471 return -2;
472 param = get_param_num_from_sym(other_sym);
473 if (param < 0) {
474 sm_msg("internal: '%s' parameter not found", other_name);
475 return -2;
478 param_name = get_param_name_var_sym(other_name, other_sym);
479 if (param_name) {
480 if (key)
481 *key = param_name;
482 return param;
484 return -2;
487 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
488 const char **key)
490 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
493 int map_to_param(const char *name, struct symbol *sym)
495 return get_param_key_from_var_sym(name, sym, NULL, NULL);
498 int get_param_num_from_sym(struct symbol *sym)
500 struct symbol *tmp;
501 int i;
503 if (!sym)
504 return UNKNOWN_SCOPE;
506 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
507 if (sym->ctype.modifiers & MOD_STATIC)
508 return FILE_SCOPE;
509 return GLOBAL_SCOPE;
512 if (!cur_func_sym) {
513 if (!parse_error) {
514 sm_msg("warn: internal. problem with scope: %s",
515 sym->ident ? sym->ident->name : "<anon var>");
517 return GLOBAL_SCOPE;
521 i = 0;
522 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
523 if (tmp == sym)
524 return i;
525 i++;
526 } END_FOR_EACH_PTR(tmp);
527 return LOCAL_SCOPE;
530 int get_param_num(struct expression *expr)
532 struct symbol *sym;
533 char *name;
535 if (!cur_func_sym)
536 return UNKNOWN_SCOPE;
537 name = expr_to_var_sym(expr, &sym);
538 free_string(name);
539 if (!sym)
540 return UNKNOWN_SCOPE;
541 return get_param_num_from_sym(sym);
544 struct symbol *get_param_sym_from_num(int num)
546 struct symbol *sym;
547 int i;
549 if (!cur_func_sym)
550 return NULL;
552 i = 0;
553 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
554 if (i++ == num)
555 return sym;
556 } END_FOR_EACH_PTR(sym);
557 return NULL;
560 char *get_name_sym_from_key(struct expression *expr, int param, const char *key, struct symbol **sym)
562 struct expression *call, *arg;
563 char *name;
565 if (sym)
566 *sym = NULL;
568 if (!expr) {
569 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
570 return NULL;
573 call = expr;
574 while (call->type == EXPR_ASSIGNMENT)
575 call = strip_expr(call->right);
577 if (call->type != EXPR_CALL)
578 return NULL;
580 if (param == -1 &&
581 expr->type == EXPR_ASSIGNMENT &&
582 expr->op == '=') {
583 name = get_variable_from_key(expr->left, key, sym);
584 if (!name || (sym && !*sym))
585 goto free;
586 } else if (param >= 0) {
587 arg = get_argument_from_call_expr(call->args, param);
588 if (!arg)
589 return NULL;
591 name = get_variable_from_key(arg, key, sym);
592 if (!name || (sym && !*sym))
593 goto free;
594 } else {
595 name = alloc_string(key);
598 return name;
599 free:
600 free_string(name);
601 return NULL;
604 char *handle_container_of_assign(struct expression *expr, struct symbol **sym)
606 struct expression *right, *orig;
607 struct symbol *type;
608 sval_t sval;
609 int param;
610 char buf[64];
612 type = get_type(expr->left);
613 if (!type || type->type != SYM_PTR)
614 return NULL;
616 right = strip_expr(expr->right);
617 if (right->type != EXPR_BINOP || right->op != '-')
618 return NULL;
620 if (!get_value(right->right, &sval) ||
621 sval.value < 0 || sval.value > MTAG_OFFSET_MASK)
622 return NULL;
624 orig = get_assigned_expr(right->left);
625 if (!orig)
626 return NULL;
627 if (orig->type != EXPR_SYMBOL)
628 return NULL;
629 param = get_param_num_from_sym(orig->symbol);
630 if (param < 0)
631 return NULL;
633 snprintf(buf, sizeof(buf), "(%lld<~$)", sval.value);
634 *sym = orig->symbol;
635 return alloc_string(buf);
638 const char *get_container_of_str(struct expression *expr)
640 struct smatch_state *state;
642 state = get_state_expr(my_id, expr);
643 if (!state)
644 return NULL;
645 return state->name;
648 static void match_assign(struct expression *expr)
650 struct symbol *param_sym;
651 char *param_name;
653 if (expr->op != '=')
654 return;
656 /* __in_fake_parameter_assign is included deliberately */
657 if (is_fake_call(expr->right) ||
658 __in_fake_struct_assign)
659 return;
661 param_name = get_param_name_sym(expr->right, &param_sym);
662 if (param_name && param_sym)
663 goto set_state;
665 param_name = handle_container_of_assign(expr, &param_sym);
666 if (param_name && param_sym)
667 goto set_state;
669 goto free;
671 set_state:
672 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
673 free:
674 free_string(param_name);
677 void register_param_key(int id)
679 my_id = id;
681 set_dynamic_states(my_id);
682 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
683 add_modification_hook(my_id, &undef);