assigned_expr: handle fake assignments better
[smatch.git] / smatch_function_ptrs.c
blobf49402d7f82975fbcdb51ba82ffe09a4d11a74f1
1 /*
2 * Copyright (C) 2013 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 * Track how functions are saved as various struct members or passed as
20 * parameters.
24 #include "scope.h"
25 #include "smatch.h"
26 #include "smatch_slist.h"
28 static int my_id;
30 static char *get_from__symbol_get(struct expression *expr)
32 struct expression *arg;
35 * typeof(&dib0070_attach) __a =
36 * ((((typeof(&dib0070_attach)) (__symbol_get("dib0070_attach")))) ?:
37 * (__request_module(true, "symbol:" "dib0070_attach"), (((typeof(&dib0070_attach))(__symbol_get("dib0070_attach"))))));
40 expr = strip_expr(expr);
42 if (expr->type != EXPR_CALL)
43 return NULL;
44 if (!sym_name_is("__symbol_get", expr->fn))
45 return NULL;
46 arg = get_argument_from_call_expr(expr->args, 0);
47 if (!arg || arg->type != EXPR_STRING)
48 return NULL;
50 return alloc_string(arg->string->data);
53 static char *get_array_ptr(struct expression *expr)
55 struct expression *array;
56 struct symbol *type;
57 char *name;
58 char buf[256];
60 array = get_array_base(expr);
62 if (array) {
63 name = get_member_name(array);
64 if (name)
65 return name;
68 /* FIXME: is_array() should probably be is_array_element() */
69 type = get_type(expr);
70 if (!array && type && type->type == SYM_ARRAY)
71 array = expr;
72 if (array) {
73 name = expr_to_var(array);
74 if (!name)
75 return NULL;
76 snprintf(buf, sizeof(buf), "%s[]", name);
77 return alloc_string(buf);
80 expr = get_assigned_expr(expr);
81 array = get_array_base(expr);
82 if (!array)
83 return NULL;
84 name = expr_to_var(array);
85 if (!name)
86 return NULL;
87 snprintf(buf, sizeof(buf), "%s[]", name);
88 free_string(name);
89 return alloc_string(buf);
92 static int is_local_symbol(struct symbol *sym)
94 if (!sym ||
95 !(sym->ctype.modifiers & MOD_TOPLEVEL))
96 return 0;
97 return 0;
100 static char *ptr_prefix(struct symbol *sym)
102 static char buf[128];
105 if (is_local_symbol(sym))
106 snprintf(buf, sizeof(buf), "%s ptr", get_function());
107 else if (sym && toplevel(sym->scope))
108 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
109 else
110 snprintf(buf, sizeof(buf), "ptr");
112 return buf;
115 char *get_returned_ptr(struct expression *expr)
117 struct symbol *type;
118 char *name;
119 char buf[256];
121 if (expr->type != EXPR_CALL)
122 return NULL;
123 if (!expr->fn || expr->fn->type != EXPR_SYMBOL)
124 return NULL;
126 type = get_type(expr);
127 if (type && type->type == SYM_PTR)
128 type = get_real_base_type(type);
129 if (!type || type->type != SYM_FN)
130 return NULL;
132 name = expr_to_var(expr->fn);
133 if (!name)
134 return NULL;
135 snprintf(buf, sizeof(buf), "r %s()", name);
136 free_string(name);
137 return alloc_string(buf);
140 char *get_fnptr_name(struct expression *expr)
142 char *name;
144 expr = strip_expr(expr);
146 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
147 if (expr->type == EXPR_PREOP && expr->op == '*')
148 expr = strip_expr(expr->unop);
150 name = get_from__symbol_get(expr);
151 if (name)
152 return name;
154 name = get_array_ptr(expr);
155 if (name)
156 return name;
158 name = get_returned_ptr(expr);
159 if (name)
160 return name;
162 name = get_member_name(expr);
163 if (name)
164 return name;
166 if (expr->type == EXPR_SYMBOL) {
167 int param;
168 char buf[256];
169 struct symbol *sym;
170 struct symbol *type;
172 param = get_param_num_from_sym(expr->symbol);
173 if (param >= 0) {
174 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
175 return alloc_string(buf);
178 name = expr_to_var_sym(expr, &sym);
179 if (!name)
180 return NULL;
181 type = get_type(expr);
182 if (type && type->type == SYM_PTR) {
183 snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
184 free_string(name);
185 return alloc_string(buf);
187 return name;
189 return expr_to_var(expr);
192 static void match_passes_function_pointer(struct expression *expr)
194 struct expression *arg, *tmp;
195 struct symbol *type;
196 char *called_name;
197 char *fn_name;
198 char ptr_name[256];
199 int i;
202 i = -1;
203 FOR_EACH_PTR(expr->args, arg) {
204 i++;
206 tmp = strip_expr(arg);
207 if (tmp->type == EXPR_PREOP && tmp->op == '&')
208 tmp = strip_expr(tmp->unop);
210 type = get_type(tmp);
211 if (type && type->type == SYM_PTR)
212 type = get_real_base_type(type);
213 if (!type || type->type != SYM_FN)
214 continue;
216 called_name = expr_to_var(expr->fn);
217 if (!called_name)
218 return;
219 fn_name = get_fnptr_name(tmp);
220 if (!fn_name)
221 goto free;
223 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
224 sql_insert_function_ptr(fn_name, ptr_name);
225 free:
226 free_string(fn_name);
227 free_string(called_name);
228 } END_FOR_EACH_PTR(arg);
232 static int get_row_count(void *_row_count, int argc, char **argv, char **azColName)
234 int *row_count = _row_count;
236 *row_count = 0;
237 if (argc != 1)
238 return 0;
239 *row_count = atoi(argv[0]);
240 return 0;
243 static int can_hold_function_ptr(struct expression *expr)
245 struct symbol *type;
247 type = get_type(expr);
248 if (!type)
249 return 0;
250 if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
251 type = get_real_base_type(type);
252 if (!type)
253 return 0;
255 if (type->type == SYM_FN)
256 return 1;
257 if (type == &ulong_ctype && expr->type == EXPR_DEREF)
258 return 1;
259 if (type == &void_ctype)
260 return 1;
261 return 0;
264 static void match_function_assign(struct expression *expr)
266 struct expression *right;
267 struct symbol *type;
268 char *fn_name;
269 char *ptr_name;
271 if (__in_fake_assign)
272 return;
274 right = strip_expr(expr->right);
275 if (right->type == EXPR_PREOP && right->op == '&')
276 right = strip_expr(right->unop);
278 if (right->type != EXPR_SYMBOL &&
279 right->type != EXPR_DEREF)
280 return;
282 if (!can_hold_function_ptr(right) ||
283 !can_hold_function_ptr(expr->left))
284 return;
286 fn_name = get_fnptr_name(right);
287 ptr_name = get_fnptr_name(expr->left);
288 if (!fn_name || !ptr_name)
289 goto free;
290 if (strcmp(fn_name, ptr_name) == 0)
291 goto free;
294 type = get_type(right);
295 if (!type)
296 return;
297 if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
298 type = get_real_base_type(type);
299 if (!type)
300 return;
302 if (type->type != SYM_FN) {
303 int count = 0;
305 /* look it up in function_ptr */
306 run_sql(get_row_count, &count,
307 "select count(*) from function_ptr where ptr = '%s'",
308 fn_name);
309 if (count == 0)
310 goto free;
313 sql_insert_function_ptr(fn_name, ptr_name);
314 free:
315 free_string(fn_name);
316 free_string(ptr_name);
319 static void match_returns_function_pointer(struct expression *expr)
321 struct symbol *type;
322 char *fn_name;
323 char ptr_name[256];
325 if (__inline_fn)
326 return;
328 type = get_real_base_type(cur_func_sym);
329 if (!type || type->type != SYM_FN)
330 return;
331 type = get_real_base_type(type);
332 if (!type || type->type != SYM_PTR)
333 return;
334 type = get_real_base_type(type);
335 if (!type || type->type != SYM_FN)
336 return;
338 if (expr->type == EXPR_PREOP && expr->op == '&')
339 expr = strip_expr(expr->unop);
341 fn_name = get_fnptr_name(expr);
342 if (!fn_name)
343 return;
344 snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
345 sql_insert_function_ptr(fn_name, ptr_name);
348 void register_function_ptrs(int id)
350 my_id = id;
352 if (!option_info)
353 return;
355 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
356 add_hook(&match_returns_function_pointer, RETURN_HOOK);
357 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
358 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);