2 * smatch/smatch_function_ptrs.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
11 * Track how functions are saved as various struct members or passed as
18 #include "smatch_slist.h"
22 static char *get_array_ptr(struct expression
*expr
)
24 struct expression
*array
;
29 array
= get_array_name(expr
);
30 /* FIXME: is_array() should probably be is_array_element() */
31 type
= get_type(expr
);
32 if (!array
&& type
&& type
->type
== SYM_ARRAY
)
35 name
= expr_to_var(array
);
38 snprintf(buf
, sizeof(buf
), "%s[]", name
);
39 return alloc_string(buf
);
42 expr
= get_assigned_expr(expr
);
43 array
= get_array_name(expr
);
46 name
= expr_to_var(array
);
49 snprintf(buf
, sizeof(buf
), "%s[]", name
);
51 return alloc_string(buf
);
54 static int is_local_symbol(struct symbol
*sym
)
56 if (!sym
|| !sym
->scope
|| !sym
->scope
->token
)
58 if (positions_eq(sym
->scope
->token
->pos
, cur_func_sym
->pos
))
63 static char *ptr_prefix(struct symbol
*sym
)
68 if (is_local_symbol(sym
))
69 snprintf(buf
, sizeof(buf
), "%s ptr", get_function());
70 else if (sym
&& toplevel(sym
->scope
))
71 snprintf(buf
, sizeof(buf
), "%s ptr", get_base_file());
73 snprintf(buf
, sizeof(buf
), "ptr");
78 char *get_fnptr_name(struct expression
*expr
)
82 expr
= strip_expr(expr
);
84 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
85 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*') {
86 struct expression
*unop
= strip_expr(expr
->unop
);
88 if (unop
->type
== EXPR_PREOP
&& unop
->op
== '*')
90 else if (unop
->type
== EXPR_SYMBOL
)
94 name
= get_array_ptr(expr
);
98 if (expr
->type
== EXPR_SYMBOL
) {
104 param
= get_param_num_from_sym(expr
->symbol
);
106 snprintf(buf
, sizeof(buf
), "%s param %d", get_function(), param
);
107 return alloc_string(buf
);
110 name
= expr_to_var_sym(expr
, &sym
);
113 type
= get_type(expr
);
114 if (type
&& type
->type
== SYM_PTR
) {
115 snprintf(buf
, sizeof(buf
), "%s %s", ptr_prefix(sym
), name
);
117 return alloc_string(buf
);
121 name
= get_member_name(expr
);
124 return expr_to_var(expr
);
127 static void match_passes_function_pointer(struct expression
*expr
)
129 struct expression
*arg
, *tmp
;
138 FOR_EACH_PTR(expr
->args
, arg
) {
141 tmp
= strip_expr(arg
);
142 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '&')
143 tmp
= strip_expr(tmp
->unop
);
145 type
= get_type(tmp
);
146 if (type
&& type
->type
== SYM_PTR
)
147 type
= get_real_base_type(type
);
148 if (!type
|| type
->type
!= SYM_FN
)
151 called_name
= expr_to_var(expr
->fn
);
154 fn_name
= get_fnptr_name(tmp
);
158 snprintf(ptr_name
, sizeof(ptr_name
), "%s param %d", called_name
, i
);
159 sql_insert_function_ptr(fn_name
, ptr_name
);
161 free_string(fn_name
);
162 free_string(called_name
);
163 } END_FOR_EACH_PTR(arg
);
167 static void match_function_assign(struct expression
*expr
)
169 struct expression
*right
;
174 if (__in_fake_assign
)
177 right
= strip_expr(expr
->right
);
178 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
179 right
= strip_expr(right
->unop
);
180 if (right
->type
!= EXPR_SYMBOL
&& right
->type
!= EXPR_DEREF
)
182 sym
= get_type(right
);
185 if (sym
->type
!= SYM_FN
&& sym
->type
!= SYM_PTR
&& sym
->type
!= SYM_ARRAY
)
187 if (sym
->type
== SYM_PTR
) {
188 sym
= get_real_base_type(sym
);
191 if (sym
->type
!= SYM_FN
&& sym
!= &void_ctype
)
195 fn_name
= get_fnptr_name(right
);
196 ptr_name
= get_fnptr_name(expr
->left
);
197 if (!fn_name
|| !ptr_name
)
199 if (strcmp(fn_name
, ptr_name
) == 0)
202 sql_insert_function_ptr(fn_name
, ptr_name
);
205 free_string(fn_name
);
206 free_string(ptr_name
);
209 void register_function_ptrs(int id
)
216 add_hook(&match_passes_function_pointer
, FUNCTION_CALL_HOOK
);
217 add_hook(&match_function_assign
, ASSIGNMENT_HOOK
);
218 add_hook(&match_function_assign
, GLOBAL_ASSIGNMENT_HOOK
);