rosenberg_funcs: warn about information leaks to the network
[smatch.git] / smatch_param_key.c
blobb7bc8856731f48546422f0102eaa7d9b62997c65
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 // FIXME: this function has been marked for deletion!
97 // get_name_sym_from_key()
99 if (!arg)
100 return NULL;
102 arg = strip_expr(arg);
104 if (strcmp(key, "$") == 0)
105 return expr_to_var_sym(arg, sym);
107 if (strcmp(key, "*$") == 0) {
108 if (arg->type == EXPR_PREOP && arg->op == '&') {
109 arg = strip_expr(arg->unop);
110 return expr_to_var_sym(arg, sym);
111 } else {
112 tmp = expr_to_var_sym(arg, sym);
113 if (!tmp)
114 return NULL;
115 ret = snprintf(buf, sizeof(buf), "*%s", tmp);
116 free_string(tmp);
117 if (ret >= sizeof(buf))
118 return NULL;
119 return alloc_string(buf);
123 if (strncmp(key, "(*$)", 4) == 0) {
124 if (arg->type == EXPR_PREOP && arg->op == '&') {
125 arg = strip_expr(arg->unop);
126 snprintf(buf, sizeof(buf), "$%s", key + 4);
127 return get_variable_from_key(arg, buf, sym);
128 } else {
129 tmp = expr_to_var_sym(arg, sym);
130 if (!tmp)
131 return NULL;
132 ret = snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
133 free_string(tmp);
134 if (ret >= sizeof(buf))
135 return NULL;
136 return alloc_string(buf);
140 while (key[0] == '*') {
141 star_cnt++;
142 key++;
145 if (key[0] == '&') {
146 address = true;
147 key++;
151 * FIXME: This is a hack.
152 * We should be able to parse expressions like (*$)->foo and *$->foo.
154 type = get_type(arg);
155 if (is_struct_ptr(type))
156 add_dot = true;
158 if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
159 arg = strip_expr(arg->unop);
160 star_cnt--;
163 if (arg->type == EXPR_PREOP && arg->op == '&') {
164 arg = strip_expr(arg->unop);
165 tmp = expr_to_var_sym(arg, sym);
166 if (!tmp)
167 return NULL;
168 ret = snprintf(buf, sizeof(buf), "%s%.*s%s.%s",
169 address ? "&" : "", star_cnt, "**********",
170 tmp, key + 3);
171 if (ret >= sizeof(buf))
172 return NULL;
173 return alloc_string(buf);
176 tmp = expr_to_var_sym(arg, sym);
177 if (!tmp)
178 return NULL;
179 ret = snprintf(buf, sizeof(buf), "%s%.*s%s%s",
180 address ? "&" : "", star_cnt, "**********", tmp, key + 1);
181 free_string(tmp);
182 if (ret >= sizeof(buf))
183 return NULL;
184 return alloc_string(buf);
187 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)
189 *vsl = NULL;
191 if (strcmp("$", key) == 0)
192 return expr_to_chunk_sym_vsl(arg, sym, vsl);
193 return get_variable_from_key(arg, key, sym);
196 static char *state_name_to_param_name(const char *state_name, const char *param_name)
198 bool address = false;
199 int star_cnt = 0;
200 int name_len;
201 char buf[256];
202 int ret;
204 name_len = strlen(param_name);
206 while (state_name[0] == '*') {
207 star_cnt++;
208 state_name++;
211 if (state_name[0] == '&') {
212 address = true;
213 state_name++;
216 /* ten out of ten stars! */
217 if (star_cnt > 10)
218 return NULL;
220 if (strncmp(state_name, "(*", 2) == 0 &&
221 strncmp(state_name + 2, param_name, name_len) == 0 &&
222 state_name[name_len + 2] == ')') {
223 ret = snprintf(buf, sizeof(buf), "%s%.*s(*$)%s",
224 address ? "&" : "",
225 star_cnt, "**********",
226 state_name + name_len + 3);
227 if (ret >= sizeof(buf))
228 return NULL;
229 return alloc_sname(buf);
232 if (strcmp(state_name, param_name) == 0) {
233 snprintf(buf, sizeof(buf), "%s%.*s$",
234 address ? "&" : "",
235 star_cnt, "**********");
236 return alloc_sname(buf);
239 /* check for '-' from "->" */
240 if (strncmp(state_name, param_name, name_len) == 0 &&
241 state_name[name_len] == '-') {
242 ret = snprintf(buf, sizeof(buf), "%s%.*s$%s",
243 address ? "&" : "",
244 star_cnt, "**********",
245 state_name + name_len);
246 if (ret >= sizeof(buf))
247 return NULL;
248 return alloc_sname(buf);
250 return NULL;
253 char *get_param_name_var_sym(const char *name, struct symbol *sym)
255 if (!sym || !sym->ident)
256 return NULL;
258 return state_name_to_param_name(name, sym->ident->name);
261 const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym)
263 struct symbol *type;
264 const char *sym_name;
265 int name_len;
266 static char buf[256];
269 * mtag_name is different from param_name because mtags can be a struct
270 * instead of a struct pointer. But we want to treat it like a pointer
271 * because really an mtag is a pointer. Or in other words, if you pass
272 * a struct foo then you want to talk about foo.bar but with an mtag
273 * you want to refer to it as foo->bar.
277 if (!sym || !sym->ident)
278 return NULL;
280 type = get_real_base_type(sym);
281 if (type && type->type == SYM_BASETYPE)
282 return "*$";
284 sym_name = sym->ident->name;
285 name_len = strlen(sym_name);
287 if (state_name[name_len] == '.' && /* check for '-' from "->" */
288 strncmp(state_name, sym_name, name_len) == 0) {
289 snprintf(buf, sizeof(buf), "$->%s", state_name + name_len + 1);
290 return buf;
293 return state_name_to_param_name(state_name, sym_name);
296 const char *get_mtag_name_expr(struct expression *expr)
298 char *name;
299 struct symbol *sym;
300 const char *ret = NULL;
302 name = expr_to_var_sym(expr, &sym);
303 if (!name || !sym)
304 goto free;
306 ret = get_mtag_name_var_sym(name, sym);
307 free:
308 free_string(name);
309 return ret;
312 char *get_param_name(struct sm_state *sm)
314 return get_param_name_var_sym(sm->name, sm->sym);
317 char *get_param_var_sym_var_sym(const char *name, struct symbol *sym, struct expression *ret_expr, struct symbol **sym_p)
319 struct smatch_state *state;
320 struct var_sym *var_sym;
321 int param;
323 *sym_p = NULL;
325 // FIXME was modified...
327 param = get_param_num_from_sym(sym);
328 if (param >= 0) {
329 *sym_p = sym;
330 return alloc_string(name);
333 state = get_state(my_id, name, sym);
334 if (state && state->data) {
335 var_sym = state->data;
336 if (!var_sym)
337 return NULL;
339 *sym_p = var_sym->sym;
340 return alloc_string(var_sym->var);
343 return swap_with_param(name, sym, sym_p);
346 char *get_param_name_sym(struct expression *expr, struct symbol **sym_p)
348 struct symbol *sym;
349 const char *ret = NULL;
350 char *name;
352 name = expr_to_var_sym(expr, &sym);
353 if (!name || !sym)
354 goto free;
356 ret = get_param_var_sym_var_sym(name, sym, NULL, sym_p);
357 free:
358 free_string(name);
359 return alloc_string(ret);
362 int get_param_key_from_var_sym(const char *name, struct symbol *sym,
363 struct expression *ret_expr,
364 const char **key)
366 const char *param_name;
367 char *other_name;
368 struct symbol *other_sym;
369 int param;
371 if (key)
372 *key = name;
374 /* straight forward param match */
375 param = get_param_num_from_sym(sym);
376 if (param >= 0) {
377 param_name = get_param_name_var_sym(name, sym);
378 if (param_name) {
379 if (key)
380 *key = param_name;
381 return param;
385 /* it's the return value */
386 if (ret_expr) {
387 struct symbol *ret_sym;
388 char *ret_str;
390 ret_str = expr_to_str_sym(ret_expr, &ret_sym);
391 if (ret_str && ret_sym == sym) {
392 param_name = state_name_to_param_name(name, ret_str);
393 if (param_name) {
394 free_string(ret_str);
395 if (key)
396 *key = param_name;
397 return -1;
400 free_string(ret_str);
403 other_name = get_param_var_sym_var_sym(name, sym, ret_expr, &other_sym);
404 if (!other_name || !other_sym)
405 return -2;
406 param = get_param_num_from_sym(other_sym);
407 if (param < 0) {
408 sm_msg("internal: '%s' parameter not found", other_name);
409 return -2;
412 param_name = get_param_name_var_sym(other_name, other_sym);
413 if (param_name) {
414 if (key)
415 *key = param_name;
416 return param;
418 return -2;
421 int get_param_key_from_sm(struct sm_state *sm, struct expression *ret_expr,
422 const char **key)
424 return get_param_key_from_var_sym(sm->name, sm->sym, ret_expr, key);
427 int map_to_param(const char *name, struct symbol *sym)
429 return get_param_key_from_var_sym(name, sym, NULL, NULL);
432 int get_param_num_from_sym(struct symbol *sym)
434 struct symbol *tmp;
435 int i;
437 if (!sym)
438 return UNKNOWN_SCOPE;
440 if (sym->ctype.modifiers & MOD_TOPLEVEL) {
441 if (sym->ctype.modifiers & MOD_STATIC)
442 return FILE_SCOPE;
443 return GLOBAL_SCOPE;
446 if (!cur_func_sym) {
447 if (!parse_error) {
448 sm_msg("warn: internal. problem with scope: %s",
449 sym->ident ? sym->ident->name : "<anon var>");
451 return GLOBAL_SCOPE;
455 i = 0;
456 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, tmp) {
457 if (tmp == sym)
458 return i;
459 i++;
460 } END_FOR_EACH_PTR(tmp);
461 return LOCAL_SCOPE;
464 int get_param_num(struct expression *expr)
466 struct symbol *sym;
467 char *name;
469 if (!cur_func_sym)
470 return UNKNOWN_SCOPE;
471 name = expr_to_var_sym(expr, &sym);
472 free_string(name);
473 if (!sym)
474 return UNKNOWN_SCOPE;
475 return get_param_num_from_sym(sym);
478 struct symbol *get_param_sym_from_num(int num)
480 struct symbol *sym;
481 int i;
483 if (!cur_func_sym)
484 return NULL;
486 i = 0;
487 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, sym) {
488 if (i++ == num)
489 return sym;
490 } END_FOR_EACH_PTR(sym);
491 return NULL;
494 char *get_name_sym_from_key(struct expression *expr, int param, const char *key, struct symbol **sym)
496 struct expression *call, *arg;
497 char *name;
499 if (sym)
500 *sym = NULL;
502 if (!expr) {
503 sm_msg("internal: null call_expr. param=%d key='%s'", param, key);
504 return NULL;
507 call = expr;
508 while (call->type == EXPR_ASSIGNMENT)
509 call = strip_expr(call->right);
511 if (call->type != EXPR_CALL)
512 return NULL;
514 if (param == -1 &&
515 expr->type == EXPR_ASSIGNMENT &&
516 expr->op == '=') {
517 name = get_variable_from_key(expr->left, key, sym);
518 if (!name || (sym && !*sym))
519 goto free;
520 } else if (param >= 0) {
521 arg = get_argument_from_call_expr(call->args, param);
522 if (!arg)
523 return NULL;
525 name = get_variable_from_key(arg, key, sym);
526 if (!name || (sym && !*sym))
527 goto free;
528 } else {
529 name = alloc_string(key);
532 return name;
533 free:
534 free_string(name);
535 return NULL;
538 static void match_assign(struct expression *expr)
540 struct symbol *param_sym;
541 char *param_name;
543 if (expr->op != '=')
544 return;
546 /* __in_fake_parameter_assign is included deliberately */
547 if (is_fake_call(expr->right) ||
548 __in_fake_struct_assign)
549 return;
551 param_name = get_param_name_sym(expr->right, &param_sym);
552 if (!param_name || !param_sym)
553 goto free;
555 set_state_expr(my_id, expr->left, alloc_var_sym_state(param_name, param_sym));
556 free:
557 free_string(param_name);
560 void register_param_key(int id)
562 my_id = id;
564 set_dynamic_states(my_id);
565 add_hook(&match_assign, ASSIGNMENT_HOOK_AFTER);
566 add_modification_hook(my_id, &undef);