*new* check_macros: find macro precedence bugs
[smatch.git] / smatch_function_hooks.c
blob8b3a420d5f3fa29edcd5e304de870a96b6a2737d
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 * return_implies_state() - For when a return value of 1 implies locked
15 * and 0 implies unlocked. etc. etc.
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include "smatch.h"
22 #include "smatch_slist.h"
23 #include "smatch_extra.h"
24 #include "smatch_function_hashtable.h"
26 struct fcall_back {
27 int type;
28 struct data_range *range;
29 func_hook *call_back;
30 void *info;
33 ALLOCATOR(fcall_back, "call backs");
34 DECLARE_PTR_LIST(call_back_list, struct fcall_back);
36 DEFINE_FUNCTION_HASHTABLE_STATIC(callback, struct fcall_back, struct call_back_list);
37 static struct hashtable *func_hash;
39 #define REGULAR_CALL 0
40 #define ASSIGN_CALL 1
41 #define RANGED_CALL 2
43 static struct fcall_back *alloc_fcall_back(int type, func_hook *call_back,
44 void *info)
46 struct fcall_back *cb;
48 cb = __alloc_fcall_back(0);
49 cb->type = type;
50 cb->call_back = call_back;
51 cb->info = info;
52 return cb;
55 void add_function_hook(const char *look_for, func_hook *call_back, void *info)
57 struct fcall_back *cb;
59 cb = alloc_fcall_back(REGULAR_CALL, call_back, info);
60 add_callback(func_hash, look_for, cb);
63 void add_function_assign_hook(const char *look_for, func_hook *call_back,
64 void *info)
66 struct fcall_back *cb;
68 cb = alloc_fcall_back(ASSIGN_CALL, call_back, info);
69 add_callback(func_hash, look_for, cb);
72 void return_implies_state(const char *look_for, long long start, long long end,
73 implication_hook *call_back, void *info)
75 struct fcall_back *cb;
77 cb = alloc_fcall_back(RANGED_CALL, (func_hook *)call_back, info);
78 cb->range = alloc_range_perm(start, end);
79 add_callback(func_hash, look_for, cb);
82 static void call_call_backs(struct call_back_list *list, int type,
83 const char *fn, struct expression *expr)
85 struct fcall_back *tmp;
87 FOR_EACH_PTR(list, tmp) {
88 if (tmp->type == type)
89 (tmp->call_back)(fn, expr, tmp->info);
90 } END_FOR_EACH_PTR(tmp);
93 static void call_ranged_call_backs(struct call_back_list *list,
94 const char *fn, struct expression *call_expr,
95 struct expression *assign_expr)
97 struct fcall_back *tmp;
99 FOR_EACH_PTR(list, tmp) {
100 ((implication_hook *)(tmp->call_back))(fn, call_expr, assign_expr, tmp->info);
101 } END_FOR_EACH_PTR(tmp);
104 static void match_function_call(struct expression *expr)
106 struct call_back_list *call_backs;
108 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
109 return;
110 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
111 if (!call_backs)
112 return;
113 call_call_backs(call_backs, REGULAR_CALL, expr->fn->symbol->ident->name,
114 expr);
117 static struct call_back_list *get_same_ranged_call_backs(struct call_back_list *list,
118 struct data_range *drange)
120 struct call_back_list *ret = NULL;
121 struct fcall_back *tmp;
123 FOR_EACH_PTR(list, tmp) {
124 if (tmp->type != RANGED_CALL)
125 continue;
126 if (tmp->range->min == drange->min && tmp->range->max == drange->max)
127 add_ptr_list(&ret, tmp);
128 } END_FOR_EACH_PTR(tmp);
129 return ret;
132 static void assign_ranged_funcs(const char *fn, struct expression *expr,
133 struct call_back_list *call_backs)
135 struct fcall_back *tmp;
136 struct sm_state *sm;
137 char *var_name;
138 struct symbol *sym;
139 struct smatch_state *extra_state;
140 struct state_list *tmp_slist;
141 struct state_list *final_states = NULL;
142 struct range_list *handled_ranges = NULL;
143 struct call_back_list *same_range_call_backs = NULL;
145 var_name = get_variable_from_expr(expr->left, &sym);
146 if (!var_name || !sym)
147 goto free;
149 FOR_EACH_PTR(call_backs, tmp) {
150 if (tmp->type != RANGED_CALL)
151 continue;
152 if (in_list_exact(handled_ranges, tmp->range))
153 continue;
154 __push_fake_cur_slist();
155 tack_on(&handled_ranges, tmp->range);
157 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
158 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
159 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
161 extra_state = alloc_extra_state_range(tmp->range->min, tmp->range->max);
162 set_extra_mod(var_name, sym, extra_state);
164 tmp_slist = __pop_fake_cur_slist();
165 merge_slist(&final_states, tmp_slist);
166 free_slist(&tmp_slist);
167 } END_FOR_EACH_PTR(tmp);
169 FOR_EACH_PTR(final_states, sm) {
170 __set_sm(sm);
171 } END_FOR_EACH_PTR(sm);
173 free_slist(&final_states);
174 free:
175 free_string(var_name);
178 void function_comparison(int comparison, struct expression *expr, long long value, int left)
180 struct call_back_list *call_backs;
181 struct fcall_back *tmp;
182 const char *fn;
183 struct data_range *value_range;
184 struct state_list *true_states = NULL;
185 struct state_list *false_states = NULL;
186 struct state_list *tmp_slist;
187 struct sm_state *sm;
189 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
190 return;
191 fn = expr->fn->symbol->ident->name;
192 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
193 if (!call_backs)
194 return;
195 value_range = alloc_range(value, value);
197 /* set true states */
198 __push_fake_cur_slist();
199 FOR_EACH_PTR(call_backs, tmp) {
200 if (tmp->type != RANGED_CALL)
201 continue;
202 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
203 continue;
204 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
205 } END_FOR_EACH_PTR(tmp);
206 tmp_slist = __pop_fake_cur_slist();
207 merge_slist(&true_states, tmp_slist);
208 free_slist(&tmp_slist);
210 /* set false states */
211 __push_fake_cur_slist();
212 FOR_EACH_PTR(call_backs, tmp) {
213 if (tmp->type != RANGED_CALL)
214 continue;
215 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
216 continue;
217 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
218 } END_FOR_EACH_PTR(tmp);
219 tmp_slist = __pop_fake_cur_slist();
220 merge_slist(&false_states, tmp_slist);
221 free_slist(&tmp_slist);
223 FOR_EACH_PTR(true_states, sm) {
224 __set_true_false_sm(sm, NULL);
225 } END_FOR_EACH_PTR(sm);
226 FOR_EACH_PTR(false_states, sm) {
227 __set_true_false_sm(NULL, sm);
228 } END_FOR_EACH_PTR(sm);
230 free_slist(&true_states);
231 free_slist(&false_states);
234 static void match_assign_call(struct expression *expr)
236 struct call_back_list *call_backs;
237 const char *fn;
238 struct expression *right;
240 right = strip_expr(expr->right);
241 if (right->fn->type != EXPR_SYMBOL || !right->fn->symbol)
242 return;
243 fn = right->fn->symbol->ident->name;
244 call_backs = search_callback(func_hash, (char *)fn);
245 if (!call_backs)
246 return;
247 call_call_backs(call_backs, ASSIGN_CALL, fn, expr);
248 assign_ranged_funcs(fn, expr, call_backs);
251 void create_function_hook_hash(void)
253 func_hash = create_function_hashtable(5000);
256 void register_function_hooks(int id)
258 add_hook(&match_function_call, FUNCTION_CALL_HOOK);
259 add_hook(&match_assign_call, CALL_ASSIGNMENT_HOOK);