*new* memset: check for memset(x, y, 0); typos
[smatch.git] / smatch_function_hooks.c
blob50abc82daf2dfb2c50873e05151733ef673fa56f
1 /*
2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are three types of function hooks:
12 * add_function_hook() - For any time a function is called.
13 * add_function_assign_hook() - foo = the_function().
14 * add_macro_assign_hook() - foo = the_macro().
15 * return_implies_state() - For when a return value of 1 implies locked
16 * and 0 implies unlocked. etc. etc.
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include "smatch.h"
23 #include "smatch_slist.h"
24 #include "smatch_extra.h"
25 #include "smatch_function_hashtable.h"
27 struct fcall_back {
28 int type;
29 struct data_range *range;
30 func_hook *call_back;
31 void *info;
34 ALLOCATOR(fcall_back, "call backs");
35 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
37 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
38 static struct hashtable *func_hash;
40 #define REGULAR_CALL 0
41 #define ASSIGN_CALL 1
42 #define RANGED_CALL 2
43 #define MACRO_ASSIGN 3
45 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
46 void *info)
48 struct fcall_back *cb;
50 cb = __alloc_fcall_back(0);
51 cb->type = type;
52 cb->call_back = call_back;
53 cb->info = info;
54 return cb;
57 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
59 struct fcall_back *cb;
61 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
62 add_callback(func_hash, look_for, cb);
65 void add_function_assign_hook(const char *look_for, func_hook *call_back,
66 void *info)
68 struct fcall_back *cb;
70 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
71 add_callback(func_hash, look_for, cb);
74 void add_macro_assign_hook(const char *look_for, func_hook *call_back,
75 void *info)
77 struct fcall_back *cb;
79 cb = alloc_fcall_back(MACRO_ASSIGN, call_back, info);
80 add_callback(func_hash, look_for, cb);
83 void return_implies_state(const char *look_for, long long start, long long end,
84 implication_hook *call_back, void *info)
86 struct fcall_back *cb;
88 cb = alloc_fcall_back(RANGED_CALL, (func_hook *)call_back, info);
89 cb->range = alloc_range_perm(start, end);
90 add_callback(func_hash, look_for, cb);
93 static void call_call_backs(struct call_back_list *list, int type,
94 const char *fn, struct expression *expr)
96 struct fcall_back *tmp;
98 FOR_EACH_PTR(list, tmp) {
99 if (tmp->type == type)
100 (tmp->call_back)(fn, expr, tmp->info);
101 } END_FOR_EACH_PTR(tmp);
104 static void call_ranged_call_backs(struct call_back_list *list,
105 const char *fn, struct expression *call_expr,
106 struct expression *assign_expr)
108 struct fcall_back *tmp;
110 FOR_EACH_PTR(list, tmp) {
111 ((implication_hook *)(tmp->call_back))(fn, call_expr, assign_expr, tmp->info);
112 } END_FOR_EACH_PTR(tmp);
115 static void match_function_call(struct expression *expr)
117 struct call_back_list *call_backs;
119 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
120 return;
121 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
122 if (!call_backs)
123 return;
124 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
125 expr);
128 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
129 struct data_range *drange)
131 struct call_back_list *ret = NULL;
132 struct fcall_back *tmp;
134 FOR_EACH_PTR(list, tmp) {
135 if (tmp->type != RANGED_CALL)
136 continue;
137 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
138 add_ptr_list(&ret, tmp);
139 } END_FOR_EACH_PTR(tmp);
140 return ret;
143 static void assign_ranged_funcs(const char *fn, struct expression *expr,
144 struct call_back_list *call_backs)
146 struct fcall_back *tmp;
147 struct sm_state *sm;
148 char *var_name;
149 struct symbol *sym;
150 struct smatch_state *extra_state;
151 struct state_list *tmp_slist;
152 struct state_list *final_states = NULL;
153 struct range_list *handled_ranges = NULL;
154 struct call_back_list *same_range_call_backs = NULL;
156 var_name = get_variable_from_expr(expr->left, &sym);
157 if (!var_name || !sym)
158 goto free;
160 FOR_EACH_PTR(call_backs, tmp) {
161 if (tmp->type != RANGED_CALL)
162 continue;
163 if (in_list_exact(handled_ranges, tmp->range))
164 continue;
165 __push_fake_cur_slist();
166 tack_on(&handled_ranges, tmp->range);
168 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
169 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
170 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
172 extra_state = alloc_extra_state_range(tmp->range->min, tmp->range->max);
173 set_extra_mod(var_name, sym, extra_state);
175 tmp_slist = __pop_fake_cur_slist();
176 merge_slist(&final_states, tmp_slist);
177 free_slist(&tmp_slist);
178 } END_FOR_EACH_PTR(tmp);
180 FOR_EACH_PTR(final_states, sm) {
181 __set_sm(sm);
182 } END_FOR_EACH_PTR(sm);
184 free_slist(&final_states);
185 free:
186 free_string(var_name);
189 void function_comparison(int comparison, struct expression *expr, long long value, int left)
191 struct call_back_list *call_backs;
192 struct fcall_back *tmp;
193 const char *fn;
194 struct data_range *value_range;
195 struct state_list *true_states = NULL;
196 struct state_list *false_states = NULL;
197 struct state_list *tmp_slist;
198 struct sm_state *sm;
200 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
201 return;
202 fn = expr->fn->symbol->ident->name;
203 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
204 if (!call_backs)
205 return;
206 value_range = alloc_range(value, value);
208 /* set true states */
209 __push_fake_cur_slist();
210 FOR_EACH_PTR(call_backs, tmp) {
211 if (tmp->type != RANGED_CALL)
212 continue;
213 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
214 continue;
215 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
216 } END_FOR_EACH_PTR(tmp);
217 tmp_slist = __pop_fake_cur_slist();
218 merge_slist(&true_states, tmp_slist);
219 free_slist(&tmp_slist);
221 /* set false states */
222 __push_fake_cur_slist();
223 FOR_EACH_PTR(call_backs, tmp) {
224 if (tmp->type != RANGED_CALL)
225 continue;
226 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
227 continue;
228 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
229 } END_FOR_EACH_PTR(tmp);
230 tmp_slist = __pop_fake_cur_slist();
231 merge_slist(&false_states, tmp_slist);
232 free_slist(&tmp_slist);
234 FOR_EACH_PTR(true_states, sm) {
235 __set_true_false_sm(sm, NULL);
236 } END_FOR_EACH_PTR(sm);
237 FOR_EACH_PTR(false_states, sm) {
238 __set_true_false_sm(NULL, sm);
239 } END_FOR_EACH_PTR(sm);
241 free_slist(&true_states);
242 free_slist(&false_states);
245 static void match_assign_call(struct expression *expr)
247 struct call_back_list *call_backs;
248 const char *fn;
249 struct expression *right;
251 right = strip_expr(expr->right);
252 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
253 return;
254 fn = right->fn->symbol->ident->name;
255 call_backs = search_callback(func_hash, (char *)fn);
256 if (!call_backs)
257 return;
258 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
259 assign_ranged_funcs(fn, expr, call_backs);
262 static void match_macro_assign(struct expression *expr)
264 struct call_back_list *call_backs;
265 const char *macro;
266 struct expression *right;
268 right = strip_expr(expr->right);
269 macro = get_macro_name(&right->pos);
270 call_backs = search_callback(func_hash, (char *)macro);
271 if (!call_backs)
272 return;
273 call_call_backs(call_backs, MACRO_ASSIGN, macro, expr);
276 void create_function_hook_hash(void)
278 func_hash = create_function_hashtable(5000);
281 void register_function_hooks(int id)
283 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
284 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);
285 add_hook(&match_macro_assign, MACRO_ASSIGNMENT_HOOK);