function_hooks: only add comparisons when needed
[smatch.git] / smatch_return_to_param.c
blob520550120e5893d704957ffa2e97920f69fab09e
1 /*
2 * Copyright (C) 2017 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 * This is for smatch_extra.c to use. It sort of like check_assigned_expr.c but
20 * more limited. Say a function returns "64min-s64max[$0->data]" and the caller
21 * does "struct whatever *p = get_data(dev);" then we want to record that p is
22 * now the same as "dev->data". Then if we update "p->foo" it means we can
23 * update "dev->data->foo" as well.
27 #include "smatch.h"
28 #include "smatch_slist.h"
29 #include "smatch_extra.h"
31 static int my_id;
32 static int link_id;
34 static struct smatch_state *alloc_my_state(const char *name, struct symbol *sym)
36 struct smatch_state *state;
38 state = __alloc_smatch_state(0);
39 state->name = alloc_sname(name);
40 state->data = sym;
41 return state;
44 static void undef(struct sm_state *sm, struct expression *mod_expr)
46 set_state(my_id, sm->name, sm->sym, &undefined);
49 char *map_call_to_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
51 struct smatch_state *state;
52 int skip;
53 char buf[256];
55 /* skip 'foo->'. This was checked in the caller. */
56 skip = strlen(sym->ident->name) + 2;
58 state = get_state(my_id, sym->ident->name, sym);
59 if (!state || !state->data)
60 return NULL;
62 snprintf(buf, sizeof(buf), "%s->%s", state->name, name + skip);
63 *new_sym = state->data;
64 return alloc_string(buf);
68 * Normally, we expect people to consistently refer to variables by the shortest
69 * name. So they use "b->a" instead of "foo->bar.a" when both point to the
70 * same memory location. However, when we're dealing across function boundaries
71 * then sometimes we pass frob(foo) which sets foo->bar.a. In that case, we
72 * translate it to the shorter name. Smatch extra updates the shorter name,
73 * which in turn updates the longer name.
76 char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
78 struct sm_state *sm;
79 int len;
80 char buf[256];
82 *new_sym = NULL;
84 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
85 if (sm->state->data != sym)
86 continue;
87 len = strlen(sm->state->name);
88 if (strncmp(name, sm->state->name, len) == 0) {
89 if (name[len] == '.')
90 continue;
92 snprintf(buf, sizeof(buf), "%s%s", sm->name, name + len);
93 *new_sym = sm->sym;
94 return alloc_string(buf);
96 } END_FOR_EACH_SM(sm);
98 return NULL;
101 static void store_mapping_helper(char *left_name, struct symbol *left_sym, struct expression *call, const char *return_string)
103 const char *p = return_string;
104 const char *end;
105 int param;
106 struct expression *arg;
107 char *name = NULL;
108 struct symbol *right_sym;
109 char buf[256];
111 while (*p && *p != '[')
112 p++;
113 if (!*p)
114 goto free;
115 p++;
116 if (*p != '$')
117 goto free;
118 p++;
119 param = atoi(p);
120 p++;
121 if (*p != '-' || *(p + 1) != '>')
122 goto free;
123 end = strchr(p, ']');
124 if (!end)
125 goto free;
127 arg = get_argument_from_call_expr(call->args, param);
128 if (!arg)
129 goto free;
130 name = expr_to_var_sym(arg, &right_sym);
131 if (!name || !right_sym)
132 goto free;
133 snprintf(buf, sizeof(buf), "%s", name);
135 if (end - p + strlen(buf) >= sizeof(buf))
136 goto free;
137 strncat(buf, p, end - p);
139 set_state(my_id, left_name, left_sym, alloc_my_state(buf, right_sym));
140 //set_state(my_id, buf, right_sym, alloc_my_state(left_name, left_sym));
142 store_link(link_id, buf, right_sym, left_name, left_sym);
144 free:
145 free_string(name);
148 void __add_return_to_param_mapping(struct expression *expr, const char *return_string)
150 struct expression *call;
151 char *left_name = NULL;
152 struct symbol *left_sym;
154 if (expr->type == EXPR_ASSIGNMENT) {
155 left_name = expr_to_var_sym(expr->left, &left_sym);
156 if (!left_name || !left_sym)
157 goto free;
159 call = strip_expr(expr->right);
160 if (call->type != EXPR_CALL)
161 goto free;
163 store_mapping_helper(left_name, left_sym, call, return_string);
164 goto free;
167 free:
168 free_string(left_name);
171 void register_return_to_param(int id)
173 my_id = id;
174 add_modification_hook(my_id, &undef);
177 void register_return_to_param_links(int id)
179 link_id = id;
180 set_up_link_functions(my_id, link_id);