kchecker: let people build a full directory
[smatch.git] / smatch_function_ptrs.c
blob4605af7b9fcb778f65202d6bb5c1a7f151f9e94e
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_array_ptr(struct expression *expr)
32 struct expression *array;
33 struct symbol *type;
34 char *name;
35 char buf[256];
37 array = get_array_name(expr);
39 if (array) {
40 name = get_member_name(array);
41 if (name)
42 return name;
45 /* FIXME: is_array() should probably be is_array_element() */
46 type = get_type(expr);
47 if (!array && type && type->type == SYM_ARRAY)
48 array = expr;
49 if (array) {
50 name = expr_to_var(array);
51 if (!name)
52 return NULL;
53 snprintf(buf, sizeof(buf), "%s[]", name);
54 return alloc_string(buf);
57 expr = get_assigned_expr(expr);
58 array = get_array_name(expr);
59 if (!array)
60 return NULL;
61 name = expr_to_var(array);
62 if (!name)
63 return NULL;
64 snprintf(buf, sizeof(buf), "%s[]", name);
65 free_string(name);
66 return alloc_string(buf);
69 static int is_local_symbol(struct symbol *sym)
71 if (!sym || !sym->scope || !sym->scope->token)
72 return 0;
73 if (positions_eq(sym->scope->token->pos, cur_func_sym->pos))
74 return 1;
75 return 0;
78 static char *ptr_prefix(struct symbol *sym)
80 static char buf[128];
83 if (is_local_symbol(sym))
84 snprintf(buf, sizeof(buf), "%s ptr", get_function());
85 else if (sym && toplevel(sym->scope))
86 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
87 else
88 snprintf(buf, sizeof(buf), "ptr");
90 return buf;
93 char *get_returned_ptr(struct expression *expr)
95 struct symbol *type;
96 char *name;
97 char buf[256];
99 if (expr->type != EXPR_CALL)
100 return NULL;
101 if (!expr->fn || expr->fn->type != EXPR_SYMBOL)
102 return NULL;
104 type = get_type(expr);
105 if (type && type->type == SYM_PTR)
106 type = get_real_base_type(type);
107 if (!type || type->type != SYM_FN)
108 return NULL;
110 name = expr_to_var(expr->fn);
111 if (!name)
112 return NULL;
113 snprintf(buf, sizeof(buf), "r %s()", name);
114 free_string(name);
115 return alloc_string(buf);
118 char *get_fnptr_name(struct expression *expr)
120 char *name;
122 expr = strip_expr(expr);
124 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
125 if (expr->type == EXPR_PREOP && expr->op == '*') {
126 struct expression *unop = strip_expr(expr->unop);
128 if (unop->type == EXPR_PREOP && unop->op == '*')
129 expr = unop;
130 else if (unop->type == EXPR_SYMBOL)
131 expr = unop;
134 name = get_array_ptr(expr);
135 if (name)
136 return name;
138 name = get_returned_ptr(expr);
139 if (name)
140 return name;
142 name = get_member_name(expr);
143 if (name)
144 return name;
146 if (expr->type == EXPR_SYMBOL) {
147 int param;
148 char buf[256];
149 struct symbol *sym;
150 struct symbol *type;
152 param = get_param_num_from_sym(expr->symbol);
153 if (param >= 0) {
154 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
155 return alloc_string(buf);
158 name = expr_to_var_sym(expr, &sym);
159 if (!name)
160 return NULL;
161 type = get_type(expr);
162 if (type && type->type == SYM_PTR) {
163 snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
164 free_string(name);
165 return alloc_string(buf);
167 return name;
169 return expr_to_var(expr);
172 static void match_passes_function_pointer(struct expression *expr)
174 struct expression *arg, *tmp;
175 struct symbol *type;
176 char *called_name;
177 char *fn_name;
178 char ptr_name[256];
179 int i;
182 i = -1;
183 FOR_EACH_PTR(expr->args, arg) {
184 i++;
186 tmp = strip_expr(arg);
187 if (tmp->type == EXPR_PREOP && tmp->op == '&')
188 tmp = strip_expr(tmp->unop);
190 type = get_type(tmp);
191 if (type && type->type == SYM_PTR)
192 type = get_real_base_type(type);
193 if (!type || type->type != SYM_FN)
194 continue;
196 called_name = expr_to_var(expr->fn);
197 if (!called_name)
198 return;
199 fn_name = get_fnptr_name(tmp);
200 if (!fn_name)
201 goto free;
203 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
204 sql_insert_function_ptr(fn_name, ptr_name);
205 free:
206 free_string(fn_name);
207 free_string(called_name);
208 } END_FOR_EACH_PTR(arg);
212 static void match_function_assign(struct expression *expr)
214 struct expression *right;
215 struct symbol *sym;
216 char *fn_name;
217 char *ptr_name;
219 if (__in_fake_assign)
220 return;
222 right = strip_expr(expr->right);
223 if (right->type == EXPR_PREOP && right->op == '&')
224 right = strip_expr(right->unop);
225 if (right->type != EXPR_SYMBOL && right->type != EXPR_DEREF && right->type != EXPR_CALL)
226 return;
227 sym = get_type(right);
228 if (!sym)
229 return;
230 if (sym->type != SYM_FN && sym->type != SYM_PTR && sym->type != SYM_ARRAY)
231 return;
232 if (sym->type == SYM_PTR) {
233 sym = get_real_base_type(sym);
234 if (!sym)
235 return;
236 if (sym->type != SYM_FN && sym != &void_ctype)
237 return;
240 fn_name = get_fnptr_name(right);
241 ptr_name = get_fnptr_name(expr->left);
242 if (!fn_name || !ptr_name)
243 goto free;
244 if (strcmp(fn_name, ptr_name) == 0)
245 goto free;
247 sql_insert_function_ptr(fn_name, ptr_name);
249 free:
250 free_string(fn_name);
251 free_string(ptr_name);
254 static void match_returns_function_pointer(struct expression *expr)
256 struct symbol *type;
257 char *fn_name;
258 char ptr_name[256];
260 if (__inline_fn)
261 return;
263 type = get_real_base_type(cur_func_sym);
264 if (!type || type->type != SYM_FN)
265 return;
266 type = get_real_base_type(type);
267 if (!type || type->type != SYM_PTR)
268 return;
269 type = get_real_base_type(type);
270 if (!type || type->type != SYM_FN)
271 return;
273 if (expr->type == EXPR_PREOP && expr->op == '&')
274 expr = strip_expr(expr->unop);
276 fn_name = get_fnptr_name(expr);
277 if (!fn_name)
278 return;
279 snprintf(ptr_name, sizeof(ptr_name), "r %s()", get_function());
280 sql_insert_function_ptr(fn_name, ptr_name);
283 void register_function_ptrs(int id)
285 my_id = id;
287 if (!option_info)
288 return;
290 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
291 add_hook(&match_returns_function_pointer, RETURN_HOOK);
292 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
293 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);