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
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
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
)
41 while(orig
[offset
] == '*' || orig
[offset
] == '(')
45 if (len
+ offset
> strlen(orig
))
47 if (orig
[offset
+ len
] != '-')
49 if (strncmp(orig
+ offset
, remove
, len
) != 0)
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
))
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
;
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
)
73 state
= get_state(my_id
, sym
->ident
->name
, sym
);
74 if (!state
|| !state
->data
)
76 var_sym
= state
->data
;
78 ret
= swap_names(name
, sym
->ident
->name
, var_sym
->var
);
82 *sym_p
= var_sym
->sym
;
86 char *get_variable_from_key(struct expression
*arg
, const char *key
, struct symbol
**sym
)
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
);
109 tmp
= expr_to_var_sym(arg
, sym
);
112 ret
= snprintf(buf
, sizeof(buf
), "*%s", tmp
);
114 if (ret
>= sizeof(buf
))
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
);
126 tmp
= expr_to_var_sym(arg
, sym
);
129 ret
= snprintf(buf
, sizeof(buf
), "(*%s)%s", tmp
, key
+ 4);
131 if (ret
>= sizeof(buf
))
133 return alloc_string(buf
);
137 while (key
[0] == '*') {
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
))
155 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&' && star_cnt
&& !add_dot
) {
156 arg
= strip_expr(arg
->unop
);
160 if (arg
->type
== EXPR_PREOP
&& arg
->op
== '&') {
161 arg
= strip_expr(arg
->unop
);
162 tmp
= expr_to_var_sym(arg
, sym
);
165 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s.%s",
166 address
? "&" : "", star_cnt
, "**********",
168 if (ret
>= sizeof(buf
))
170 return alloc_string(buf
);
173 tmp
= expr_to_var_sym(arg
, sym
);
176 ret
= snprintf(buf
, sizeof(buf
), "%s%.*s%s%s",
177 address
? "&" : "", star_cnt
, "**********", tmp
, key
+ 1);
179 if (ret
>= sizeof(buf
))
181 return alloc_string(buf
);
184 char *get_chunk_from_key(struct expression
*arg
, char *key
, struct symbol
**sym
, struct var_sym_list
**vsl
)
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;
201 name_len
= strlen(param_name
);
203 while (state_name
[0] == '*') {
208 if (state_name
[0] == '&') {
213 /* ten out of ten stars! */
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",
222 star_cnt
, "**********",
223 state_name
+ name_len
+ 3);
224 if (ret
>= sizeof(buf
))
226 return alloc_sname(buf
);
229 if (strcmp(state_name
, param_name
) == 0) {
230 snprintf(buf
, sizeof(buf
), "%s%.*s$",
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",
241 star_cnt
, "**********",
242 state_name
+ name_len
);
243 if (ret
>= sizeof(buf
))
245 return alloc_sname(buf
);
250 char *get_param_name_var_sym(const char *name
, struct symbol
*sym
)
252 if (!sym
|| !sym
->ident
)
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
)
261 const char *sym_name
;
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
)
277 type
= get_real_base_type(sym
);
278 if (type
&& type
->type
== SYM_BASETYPE
)
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);
290 return state_name_to_param_name(state_name
, sym_name
);
293 const char *get_mtag_name_expr(struct expression
*expr
)
297 const char *ret
= NULL
;
299 name
= expr_to_var_sym(expr
, &sym
);
303 ret
= get_mtag_name_var_sym(name
, sym
);
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
;
322 // FIXME was modified...
324 param
= get_param_num_from_sym(sym
);
327 return alloc_string(name
);
330 state
= get_state(my_id
, name
, sym
);
331 if (state
&& state
->data
) {
332 var_sym
= state
->data
;
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
)
346 const char *ret
= NULL
;
349 name
= expr_to_var_sym(expr
, &sym
);
353 ret
= get_param_var_sym_var_sym(name
, sym
, NULL
, sym_p
);
356 return alloc_string(ret
);
359 int get_param_key_from_var_sym(const char *name
, struct symbol
*sym
,
360 struct expression
*ret_expr
,
363 const char *param_name
;
365 struct symbol
*other_sym
;
371 /* straight forward param match */
372 param
= get_param_num_from_sym(sym
);
374 param_name
= get_param_name_var_sym(name
, sym
);
382 /* it's the return value */
384 struct symbol
*ret_sym
;
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
);
391 free_string(ret_str
);
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
)
403 param
= get_param_num_from_sym(other_sym
);
405 sm_msg("internal: '%s' parameter not found", other_name
);
409 param_name
= get_param_name_var_sym(other_name
, other_sym
);
418 int get_param_key_from_sm(struct sm_state
*sm
, struct expression
*ret_expr
,
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
)
435 return UNKNOWN_SCOPE
;
437 if (sym
->ctype
.modifiers
& MOD_TOPLEVEL
) {
438 if (sym
->ctype
.modifiers
& MOD_STATIC
)
445 sm_msg("warn: internal. problem with scope: %s",
446 sym
->ident
? sym
->ident
->name
: "<anon var>");
453 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, tmp
) {
457 } END_FOR_EACH_PTR(tmp
);
461 int get_param_num(struct expression
*expr
)
467 return UNKNOWN_SCOPE
;
468 name
= expr_to_var_sym(expr
, &sym
);
471 return UNKNOWN_SCOPE
;
472 return get_param_num_from_sym(sym
);
475 struct symbol
*get_param_sym_from_num(int num
)
484 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, sym
) {
487 } END_FOR_EACH_PTR(sym
);
491 char *get_name_sym_from_key(struct expression
*expr
, int param
, const char *key
, struct symbol
**sym
)
493 struct expression
*call
, *arg
;
500 sm_msg("internal: null call_expr. param=%d key='%s'", param
, key
);
505 while (call
->type
== EXPR_ASSIGNMENT
)
506 call
= strip_expr(call
->right
);
508 if (call
->type
!= EXPR_CALL
)
512 expr
->type
== EXPR_ASSIGNMENT
&&
514 name
= get_variable_from_key(expr
->left
, key
, sym
);
515 if (!name
|| (sym
&& !*sym
))
517 } else if (param
>= 0) {
518 arg
= get_argument_from_call_expr(call
->args
, param
);
522 name
= get_variable_from_key(arg
, key
, sym
);
523 if (!name
|| (sym
&& !*sym
))
526 name
= alloc_string(key
);
535 static void match_assign(struct expression
*expr
)
537 struct symbol
*param_sym
;
543 /* __in_fake_parameter_assign is included deliberately */
544 if (is_fake_call(expr
->right
) ||
545 __in_fake_struct_assign
)
548 param_name
= get_param_name_sym(expr
->right
, ¶m_sym
);
549 if (!param_name
|| !param_sym
)
552 set_state_expr(my_id
, expr
->left
, alloc_var_sym_state(param_name
, param_sym
));
554 free_string(param_name
);
557 void register_param_key(int id
)
561 set_dynamic_states(my_id
);
562 add_hook(&match_assign
, ASSIGNMENT_HOOK_AFTER
);
563 add_modification_hook(my_id
, &undef
);