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
;
28 array
= get_array_name(expr
);
30 name
= expr_to_var(array
);
33 snprintf(buf
, sizeof(buf
), "%s[]", name
);
34 return alloc_string(buf
);
37 expr
= get_assigned_expr(expr
);
38 array
= get_array_name(expr
);
41 name
= expr_to_var(array
);
44 snprintf(buf
, sizeof(buf
), "%s[]", name
);
46 return alloc_string(buf
);
49 static int is_local_symbol(struct symbol
*sym
)
51 if (!sym
|| !sym
->scope
|| !sym
->scope
->token
)
53 if (positions_eq(sym
->scope
->token
->pos
, cur_func_sym
->pos
))
58 static char *ptr_prefix(struct symbol
*sym
)
63 if (is_local_symbol(sym
))
64 snprintf(buf
, sizeof(buf
), "%s ptr", get_function());
65 else if (sym
&& toplevel(sym
->scope
))
66 snprintf(buf
, sizeof(buf
), "%s ptr", get_base_file());
68 snprintf(buf
, sizeof(buf
), "ptr");
73 char *get_fnptr_name(struct expression
*expr
)
77 expr
= strip_expr(expr
);
79 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
80 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '*') {
81 struct expression
*unop
= strip_expr(expr
->unop
);
83 if (unop
->type
== EXPR_PREOP
&& unop
->op
== '*')
85 else if (unop
->type
== EXPR_SYMBOL
)
89 name
= get_array_ptr(expr
);
93 if (expr
->type
== EXPR_SYMBOL
) {
99 param
= get_param_num_from_sym(expr
->symbol
);
101 snprintf(buf
, sizeof(buf
), "%s param %d", get_function(), param
);
102 return alloc_string(buf
);
105 name
= expr_to_var_sym(expr
, &sym
);
108 type
= get_type(expr
);
109 if (type
&& type
->type
== SYM_PTR
) {
110 snprintf(buf
, sizeof(buf
), "%s %s", ptr_prefix(sym
), name
);
112 return alloc_string(buf
);
116 name
= get_member_name(expr
);
119 return expr_to_var(expr
);
122 static void match_passes_function_pointer(struct expression
*expr
)
124 struct expression
*arg
, *tmp
;
133 FOR_EACH_PTR(expr
->args
, arg
) {
136 tmp
= strip_expr(arg
);
137 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '&')
138 tmp
= strip_expr(tmp
->unop
);
140 type
= get_type(tmp
);
141 if (type
&& type
->type
== SYM_PTR
)
142 type
= get_real_base_type(type
);
143 if (!type
|| type
->type
!= SYM_FN
)
146 called_name
= expr_to_var(expr
->fn
);
149 fn_name
= get_fnptr_name(tmp
);
153 snprintf(ptr_name
, sizeof(ptr_name
), "%s param %d", called_name
, i
);
154 sql_insert_function_ptr(fn_name
, ptr_name
);
156 free_string(fn_name
);
157 free_string(called_name
);
158 } END_FOR_EACH_PTR(arg
);
162 static void match_function_assign(struct expression
*expr
)
164 struct expression
*right
;
169 right
= strip_expr(expr
->right
);
170 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
171 right
= strip_expr(right
->unop
);
172 if (right
->type
!= EXPR_SYMBOL
&& right
->type
!= EXPR_DEREF
)
174 sym
= get_type(right
);
177 if (sym
->type
!= SYM_FN
&& sym
->type
!= SYM_PTR
)
179 if (sym
->type
== SYM_PTR
) {
180 sym
= get_real_base_type(sym
);
183 if (sym
->type
!= SYM_FN
&& sym
!= &void_ctype
)
187 fn_name
= get_fnptr_name(right
);
188 ptr_name
= get_fnptr_name(expr
->left
);
189 if (!fn_name
|| !ptr_name
)
192 sql_insert_function_ptr(fn_name
, ptr_name
);
195 free_string(fn_name
);
196 free_string(ptr_name
);
199 void register_function_ptrs(int id
)
206 add_hook(&match_passes_function_pointer
, FUNCTION_CALL_HOOK
);
207 add_hook(&match_function_assign
, ASSIGNMENT_HOOK
);
208 add_hook(&match_function_assign
, GLOBAL_ASSIGNMENT_HOOK
);