comparison: inherit links when the comparison is set from a function call
[smatch.git] / smatch_function_ptrs.c
blob3738805bad2a320f53be1ca636217650d6cf5067
1 /*
2 * smatch/smatch_function_ptrs.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * Track how functions are saved as various struct members or passed as
12 * parameters.
16 #include "smatch.h"
17 #include "smatch_slist.h"
19 static int my_id;
21 static char *get_array_ptr(struct expression *expr)
23 struct expression *array;
24 char *name;
25 char buf[256];
27 array = get_array_name(expr);
28 if (array) {
29 name = expr_to_var(array);
30 if (!name)
31 return NULL;
32 snprintf(buf, sizeof(buf), "%s[]", name);
33 return alloc_string(buf);
36 expr = get_assigned_expr(expr);
37 array = get_array_name(expr);
38 if (!array)
39 return NULL;
40 name = expr_to_var(array);
41 if (!name)
42 return NULL;
43 snprintf(buf, sizeof(buf), "%s[]", name);
44 free_string(name);
45 return alloc_string(buf);
48 char *get_fnptr_name(struct expression *expr)
50 char *name;
52 expr = strip_expr(expr);
54 /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
55 if (expr->type == EXPR_PREOP && expr->op == '*') {
56 struct expression *unop = strip_expr(expr->unop);
58 if (unop->type == EXPR_PREOP && unop->op == '*')
59 expr = unop;
60 else if (unop->type == EXPR_SYMBOL)
61 expr = unop;
64 name = get_array_ptr(expr);
65 if (name)
66 return name;
68 if (expr->type == EXPR_SYMBOL) {
69 int param;
70 char buf[256];
72 param = get_param_num_from_sym(expr->symbol);
73 if (param >= 0) {
74 snprintf(buf, sizeof(buf), "%s param %d", get_function(), param);
75 return alloc_string(buf);
78 return expr_to_var(expr);
80 name = get_member_name(expr);
81 if (name)
82 return name;
83 return expr_to_var(expr);
86 static void match_passes_function_pointer(struct expression *expr)
88 struct expression *arg, *tmp;
89 struct symbol *type;
90 char *called_name;
91 char *fn_name;
92 char ptr_name[256];
93 int i;
96 i = -1;
97 FOR_EACH_PTR(expr->args, arg) {
98 i++;
100 tmp = strip_expr(arg);
101 if (tmp->type == EXPR_PREOP && tmp->op == '&')
102 tmp = strip_expr(tmp->unop);
104 type = get_type(tmp);
105 if (type && type->type == SYM_PTR)
106 type = get_real_base_type(type);
107 if (!type || type->type != SYM_FN)
108 continue;
110 called_name = expr_to_var(expr->fn);
111 if (!called_name)
112 return;
113 fn_name = get_fnptr_name(tmp);
114 if (!fn_name)
115 goto free;
117 snprintf(ptr_name, sizeof(ptr_name), "%s param %d", called_name, i);
118 sql_insert_function_ptr(fn_name, ptr_name);
119 free:
120 free_string(fn_name);
121 free_string(called_name);
122 } END_FOR_EACH_PTR(arg);
126 static void match_function_assign(struct expression *expr)
128 struct expression *right;
129 struct symbol *sym;
130 char *fn_name;
131 char *ptr_name;
133 right = strip_expr(expr->right);
134 if (right->type == EXPR_PREOP && right->op == '&')
135 right = strip_expr(right->unop);
136 if (right->type != EXPR_SYMBOL)
137 return;
138 sym = get_type(right);
139 if (!sym)
140 return;
141 if (sym->type != SYM_FN && sym->type != SYM_PTR)
142 return;
143 if (sym->type == SYM_PTR) {
144 sym = get_real_base_type(sym);
145 if (!sym)
146 return;
147 if (sym->type != SYM_FN && sym != &void_ctype)
148 return;
151 fn_name = get_fnptr_name(right);
152 ptr_name = get_fnptr_name(expr->left);
153 if (!fn_name || !ptr_name)
154 goto free;
156 sql_insert_function_ptr(fn_name, ptr_name);
158 free:
159 free_string(fn_name);
160 free_string(ptr_name);
163 void register_function_ptrs(int id)
165 my_id = id;
167 if (!option_info)
168 return;
170 add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
171 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
172 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);