Handle once through loops differently
[smatch.git] / smatch_function_hooks.c
blob99893b410f097091bb03fc5a6524bdfb182ae823
1 #define _GNU_SOURCE
2 #include <search.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include "smatch.h"
6 #include "smatch_slist.h"
7 #include "smatch_extra.h"
9 ALLOCATOR(fcall_back, "call backs");
11 static struct hsearch_data func_hash;
13 static struct state_list *cond_true = NULL;
14 static struct state_list *cond_false = NULL;
15 static int in_hook = 0;
16 #define REGULAR_CALL 0
17 #define CONDITIONAL_CALL 1
18 #define ASSIGN_CALL 2
20 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
21 void *info)
23 struct fcall_back *cb;
25 cb = __alloc_fcall_back(0);
26 cb->type = type;
27 cb->call_back = call_back;
28 cb->info = info;
29 return cb;
32 static struct call_back_list *get_call_backs(const char *look_for)
34 ENTRY e, *ep;
36 e.key = (char *)look_for;
37 hsearch_r(e, FIND, &ep, &func_hash);
38 if (!ep)
39 return NULL;
40 return (struct call_back_list *)ep->data;
43 static void add_cb_hook(const char *look_for, struct fcall_back *cb)
45 ENTRY e, *ep;
46 char *old_key = NULL;
48 e.key = alloc_string(look_for);
49 hsearch_r(e, FIND, &ep, &func_hash);
50 if (!ep) {
51 struct call_back_list *list = NULL;
53 add_ptr_list(&list, cb);
54 e.data = list;
55 } else {
56 old_key = e.key;
57 e.key = ep->key;
58 add_ptr_list((struct call_back_list **)&ep->data, cb);
59 e.data = ep->data;
61 if (!hsearch_r(e, ENTER, &ep, &func_hash)) {
62 printf("Error hash table too small in smatch_function_hooks.c\n");
63 exit(1);
65 free_string(old_key);
68 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
70 struct fcall_back *cb;
72 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
73 add_cb_hook(look_for, cb);
76 void add_conditional_hook(const char *look_for, func_hook *call_back,
77 void *info)
79 struct fcall_back *cb;
81 cb = alloc_fcall_back(CONDITIONAL_CALL, call_back, info);
82 add_cb_hook(look_for, cb);
85 void add_function_assign_hook(const char *look_for, func_hook *call_back,
86 void *info)
88 struct fcall_back *cb;
90 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
91 add_cb_hook(look_for, cb);
94 static void call_call_backs(struct call_back_list *list, int type,
95 const char *fn, struct expression *expr)
97 struct fcall_back *tmp;
99 FOR_EACH_PTR(list, tmp) {
100 if (tmp->type == type)
101 (tmp->call_back)(fn, expr, tmp->info);
102 } END_FOR_EACH_PTR(tmp);
105 static void match_function_call(struct expression *expr)
107 struct call_back_list *call_backs;
109 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
110 return;
111 call_backs = get_call_backs(expr->fn->symbol->ident->name);
112 if (!call_backs)
113 return;
114 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
115 expr);
118 static void assign_condition_funcs(const char *fn, struct expression *expr,
119 struct call_back_list *call_backs)
121 struct fcall_back *tmp;
122 struct sm_state *sm;
123 int conditional = 0;
124 char *var_name;
125 struct symbol *sym;
126 struct smatch_state *zero_state, *non_zero_state;
128 var_name = get_variable_from_expr(expr->left, &sym);
129 if (!var_name || !sym)
130 goto free;
132 in_hook = 1;
133 FOR_EACH_PTR(call_backs, tmp) {
134 if (tmp->type != CONDITIONAL_CALL)
135 continue;
137 conditional = 1;
138 (tmp->call_back)(fn, expr->right, tmp->info);
139 } END_FOR_EACH_PTR(tmp);
140 if (conditional) {
141 zero_state = alloc_extra_state(0);
142 non_zero_state = alloc_extra_state(UNDEFINED);
143 non_zero_state = add_filter(non_zero_state, 0);
144 set_cond_states(var_name, SMATCH_EXTRA, sym, non_zero_state, zero_state);
146 in_hook = 0;
148 if (!conditional)
149 goto free;
151 merge_slist(&cond_true, cond_false);
153 FOR_EACH_PTR(cond_true, sm) {
154 __set_state(sm);
155 } END_FOR_EACH_PTR(sm);
156 free_slist(&cond_true);
157 free_slist(&cond_false);
158 free:
159 free_string(var_name);
163 void __match_initializer_call(struct symbol *sym)
165 struct call_back_list *call_backs;
166 struct expression *initializer = sym->initializer;
167 struct expression *e_assign, *e_symbol;
168 const char *fn;
170 if (initializer->fn->type != EXPR_SYMBOL
171 || !initializer->fn->symbol)
172 return;
173 fn = initializer->fn->symbol->ident->name;
174 call_backs = get_call_backs(fn);
175 if (!call_backs)
176 return;
178 e_assign = alloc_expression(initializer->pos, EXPR_ASSIGNMENT);
179 e_symbol = alloc_expression(initializer->pos, EXPR_SYMBOL);
180 e_symbol->symbol = sym;
181 e_symbol->symbol_name = sym->ident;
182 e_assign->left = e_symbol;
183 e_assign->right = initializer;
184 call_call_backs(call_backs, ASSIGN_CALL, fn, e_assign);
185 assign_condition_funcs(fn, e_assign, call_backs);
188 static void match_assign_call(struct expression *expr)
190 struct call_back_list *call_backs;
191 const char *fn;
193 if (expr->right->fn->type != EXPR_SYMBOL || !expr->right->fn->symbol)
194 return;
195 fn = expr->right->fn->symbol->ident->name;
196 call_backs = get_call_backs(fn);
197 if (!call_backs)
198 return;
199 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
200 assign_condition_funcs(fn, expr, call_backs);
203 static void match_conditional_call(struct expression *expr)
205 struct call_back_list *call_backs;
206 struct fcall_back *tmp;
207 struct sm_state *sm;
208 const char *fn;
210 if (expr->type != EXPR_CALL)
211 return;
213 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
214 return;
216 fn = expr->fn->symbol->ident->name;
217 call_backs = get_call_backs(fn);
218 if (!call_backs)
219 return;
220 in_hook = 1;
221 FOR_EACH_PTR(call_backs, tmp) {
222 if (tmp->type != CONDITIONAL_CALL)
223 continue;
225 (tmp->call_back)(fn, expr, tmp->info);
227 FOR_EACH_PTR(cond_true, sm) {
228 __set_true_false_sm(sm, NULL);
229 } END_FOR_EACH_PTR(sm);
230 free_slist(&cond_true);
232 FOR_EACH_PTR(cond_false, sm) {
233 __set_true_false_sm(NULL, sm);
234 } END_FOR_EACH_PTR(sm);
235 free_slist(&cond_false);
237 } END_FOR_EACH_PTR(tmp);
238 in_hook = 0;
241 void set_cond_states(const char *name, int owner, struct symbol *sym,
242 struct smatch_state *true_state,
243 struct smatch_state *false_state)
245 if (!in_hook) {
246 printf("Error: call set_true_false_states() not"
247 "set_cond_states()\n");
248 return;
251 if (debug_states) {
252 struct smatch_state *tmp;
254 tmp = get_state(name, owner, sym);
255 SM_DEBUG("%d set_true_false '%s'. Was %s. Now T:%s F:%s\n",
256 get_lineno(), name, show_state(tmp),
257 show_state(true_state), show_state(false_state));
260 if (true_state) {
261 set_state_slist(&cond_true, name, owner, sym, true_state);
263 if (false_state)
264 set_state_slist(&cond_false, name, owner, sym, false_state);
267 void create_function_hash(void)
269 hcreate_r(10000, &func_hash); // Apparently 1000 is too few...
272 void register_function_hooks(int id)
274 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
275 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
276 add_hook(&match_conditional_call, CONDITION_HOOK);