unreachable: silence "not actually initialized" false positives
[smatch.git] / smatch_function_ptrs.c
blob169ee349436cad258a67639ffb9f52bf825cc331
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);
38 /* FIXME: is_array() should probably be is_array_element() */
39 type = get_type(expr);
40 if (!array && type && type->type == SYM_ARRAY)
41 array = expr;
42 if (array) {
43 name = expr_to_var(array);
44 if (!name)
45 return NULL;
46 snprintf(buf, sizeof(buf), "%s[]", name);
47 return alloc_string(buf);
50 expr = get_assigned_expr(expr);
51 array = get_array_name(expr);
52 if (!array)
53 return NULL;
54 name = expr_to_var(array);
55 if (!name)
56 return NULL;
57 snprintf(buf, sizeof(buf), "%s[]", name);
58 free_string(name);
59 return alloc_string(buf);
62 static int is_local_symbol(struct symbol *sym)
64 if (!sym || !sym->scope || !sym->scope->token)
65 return 0;
66 if (positions_eq(sym->scope->token->pos, cur_func_sym->pos))
67 return 1;
68 return 0;
71 static char *ptr_prefix(struct symbol *sym)
73 static char buf[128];
76 if (is_local_symbol(sym))
77 snprintf(buf, sizeof(buf), "%s ptr", get_function());
78 else if (sym && toplevel(sym->scope))
79 snprintf(buf, sizeof(buf), "%s ptr", get_base_file());
80 else
81 snprintf(buf, sizeof(buf), "ptr");
83 return buf;
86 char *get_fnptr_name(struct expression *expr)
88 char *name;
90 expr = strip_expr(expr);
92 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
93 if (expr->type == EXPR_PREOP && expr->op == '*') {
94 struct expression *unop = strip_expr(expr->unop);
96 if (unop->type == EXPR_PREOP && unop->op == '*')
97 expr = unop;
98 else if (unop->type == EXPR_SYMBOL)
99 expr = unop;
102 name = get_array_ptr(expr);
103 if (name)
104 return name;
106 if (expr->type == EXPR_SYMBOL) {
107 int param;
108 char buf[256];
109 struct symbol *sym;
110 struct symbol *type;
112 param = get_param_num_from_sym(expr->symbol);
113 if (param >= 0) {
114 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
115 return alloc_string(buf);
118 name = expr_to_var_sym(expr, &sym);
119 if (!name)
120 return NULL;
121 type = get_type(expr);
122 if (type && type->type == SYM_PTR) {
123 snprintf(buf, sizeof(buf), "%s %s", ptr_prefix(sym), name);
124 free_string(name);
125 return alloc_string(buf);
127 return name;
129 name = get_member_name(expr);
130 if (name)
131 return name;
132 return expr_to_var(expr);
135 static void match_passes_function_pointer(struct expression *expr)
137 struct expression *arg, *tmp;
138 struct symbol *type;
139 char *called_name;
140 char *fn_name;
141 char ptr_name[256];
142 int i;
145 i = -1;
146 FOR_EACH_PTR(expr->args, arg) {
147 i++;
149 tmp = strip_expr(arg);
150 if (tmp->type == EXPR_PREOP && tmp->op == '&')
151 tmp = strip_expr(tmp->unop);
153 type = get_type(tmp);
154 if (type && type->type == SYM_PTR)
155 type = get_real_base_type(type);
156 if (!type || type->type != SYM_FN)
157 continue;
159 called_name = expr_to_var(expr->fn);
160 if (!called_name)
161 return;
162 fn_name = get_fnptr_name(tmp);
163 if (!fn_name)
164 goto free;
166 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
167 sql_insert_function_ptr(fn_name, ptr_name);
168 free:
169 free_string(fn_name);
170 free_string(called_name);
171 } END_FOR_EACH_PTR(arg);
175 static void match_function_assign(struct expression *expr)
177 struct expression *right;
178 struct symbol *sym;
179 char *fn_name;
180 char *ptr_name;
182 if (__in_fake_assign)
183 return;
185 right = strip_expr(expr->right);
186 if (right->type == EXPR_PREOP && right->op == '&')
187 right = strip_expr(right->unop);
188 if (right->type != EXPR_SYMBOL && right->type != EXPR_DEREF)
189 return;
190 sym = get_type(right);
191 if (!sym)
192 return;
193 if (sym->type != SYM_FN && sym->type != SYM_PTR && sym->type != SYM_ARRAY)
194 return;
195 if (sym->type == SYM_PTR) {
196 sym = get_real_base_type(sym);
197 if (!sym)
198 return;
199 if (sym->type != SYM_FN && sym != &void_ctype)
200 return;
203 fn_name = get_fnptr_name(right);
204 ptr_name = get_fnptr_name(expr->left);
205 if (!fn_name || !ptr_name)
206 goto free;
207 if (strcmp(fn_name, ptr_name) == 0)
208 goto free;
210 sql_insert_function_ptr(fn_name, ptr_name);
212 free:
213 free_string(fn_name);
214 free_string(ptr_name);
217 void register_function_ptrs(int id)
219 my_id = id;
221 if (!option_info)
222 return;
224 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
225 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
226 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);