2 * sparse/smatch_function_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
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_conditional_hook() - For when the return value implies something.
15 * For example a return value of 1 might mean
16 * a lock is held and 0 means it is not held.
24 #include "smatch_slist.h"
25 #include "smatch_extra.h"
29 struct data_range
*range
;
34 ALLOCATOR(fcall_back
, "call backs");
35 DECLARE_PTR_LIST(call_back_list
, struct fcall_back
);
37 static struct hsearch_data func_hash
;
39 #define REGULAR_CALL 0
40 #define CONDITIONAL_CALL 1
44 static struct fcall_back
*alloc_fcall_back(int type
, func_hook
*call_back
,
47 struct fcall_back
*cb
;
49 cb
= __alloc_fcall_back(0);
51 cb
->call_back
= call_back
;
56 static struct call_back_list
*get_call_backs(const char *look_for
)
60 e
.key
= (char *)look_for
;
61 hsearch_r(e
, FIND
, &ep
, &func_hash
);
64 return (struct call_back_list
*)ep
->data
;
67 static void add_cb_hook(const char *look_for
, struct fcall_back
*cb
)
72 e
.key
= alloc_string(look_for
);
73 hsearch_r(e
, FIND
, &ep
, &func_hash
);
75 struct call_back_list
*list
= NULL
;
77 add_ptr_list(&list
, cb
);
82 add_ptr_list((struct call_back_list
**)&ep
->data
, cb
);
85 if (!hsearch_r(e
, ENTER
, &ep
, &func_hash
)) {
86 printf("Error hash table too small in smatch_function_hooks.c\n");
92 void add_function_hook(const char *look_for
, func_hook
*call_back
, void *info
)
94 struct fcall_back
*cb
;
96 cb
= alloc_fcall_back(REGULAR_CALL
, call_back
, info
);
97 add_cb_hook(look_for
, cb
);
100 void add_conditional_hook(const char *look_for
, func_hook
*call_back
,
103 struct fcall_back
*cb
;
105 cb
= alloc_fcall_back(CONDITIONAL_CALL
, call_back
, info
);
106 add_cb_hook(look_for
, cb
);
109 void add_function_assign_hook(const char *look_for
, func_hook
*call_back
,
112 struct fcall_back
*cb
;
114 cb
= alloc_fcall_back(ASSIGN_CALL
, call_back
, info
);
115 add_cb_hook(look_for
, cb
);
118 void return_implies_state(const char *look_for
, long long start
, long long end
,
119 func_hook
*call_back
, void *info
)
121 struct fcall_back
*cb
;
123 cb
= alloc_fcall_back(RANGED_CALL
, call_back
, info
);
124 cb
->range
= alloc_range_perm(start
, end
);
125 add_cb_hook(look_for
, cb
);
128 static void call_call_backs(struct call_back_list
*list
, int type
,
129 const char *fn
, struct expression
*expr
)
131 struct fcall_back
*tmp
;
133 FOR_EACH_PTR(list
, tmp
) {
134 if (tmp
->type
== type
)
135 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
136 } END_FOR_EACH_PTR(tmp
);
139 static void match_function_call(struct expression
*expr
)
141 struct call_back_list
*call_backs
;
143 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
145 call_backs
= get_call_backs(expr
->fn
->symbol
->ident
->name
);
148 call_call_backs(call_backs
, REGULAR_CALL
, expr
->fn
->symbol
->ident
->name
,
152 static void assign_condition_funcs(const char *fn
, struct expression
*expr
,
153 struct call_back_list
*call_backs
)
155 struct fcall_back
*tmp
;
160 struct smatch_state
*zero_state
, *non_zero_state
;
162 var_name
= get_variable_from_expr(expr
->left
, &sym
);
163 if (!var_name
|| !sym
)
166 __fake_conditions
= 1;
167 FOR_EACH_PTR(call_backs
, tmp
) {
168 if (tmp
->type
!= CONDITIONAL_CALL
)
172 (tmp
->call_back
)(fn
, expr
->right
, tmp
->info
);
173 } END_FOR_EACH_PTR(tmp
);
175 zero_state
= alloc_extra_state(0);
176 non_zero_state
= add_filter(extra_undefined(), 0);
177 set_true_false_states(SMATCH_EXTRA
, var_name
, sym
, non_zero_state
, zero_state
);
179 __fake_conditions
= 0;
184 merge_slist(&__fake_cond_true
, __fake_cond_false
);
186 FOR_EACH_PTR(__fake_cond_true
, sm
) {
188 } END_FOR_EACH_PTR(sm
);
189 free_slist(&__fake_cond_true
);
190 free_slist(&__fake_cond_false
);
192 free_string(var_name
);
195 static struct call_back_list
*get_same_ranged_call_backs(struct call_back_list
*list
,
196 struct data_range
*drange
)
198 struct call_back_list
*ret
= NULL
;
199 struct fcall_back
*tmp
;
201 FOR_EACH_PTR(list
, tmp
) {
202 if (tmp
->range
->min
== drange
->min
&& tmp
->range
->max
== drange
->max
)
203 add_ptr_list(&ret
, tmp
);
204 } END_FOR_EACH_PTR(tmp
);
208 static void assign_ranged_funcs(const char *fn
, struct expression
*expr
,
209 struct call_back_list
*call_backs
)
211 struct fcall_back
*tmp
;
215 struct smatch_state
*extra_state
;
216 struct state_list
*final_states
= NULL
;
217 struct range_list
*handled_ranges
= NULL
;
218 struct call_back_list
*same_range_call_backs
= NULL
;
220 var_name
= get_variable_from_expr(expr
->left
, &sym
);
221 if (!var_name
|| !sym
)
225 FOR_EACH_PTR(call_backs
, tmp
) {
226 if (tmp
->type
!= RANGED_CALL
)
228 if (in_list_exact(handled_ranges
, tmp
->range
))
230 tack_on(&handled_ranges
, tmp
->range
);
232 same_range_call_backs
= get_same_ranged_call_backs(call_backs
, tmp
->range
);
233 call_call_backs(same_range_call_backs
, RANGED_CALL
, fn
, expr
->right
);
234 __free_ptr_list((struct ptr_list
**)&same_range_call_backs
);
236 extra_state
= alloc_extra_state_range(tmp
->range
->min
, tmp
->range
->max
);
237 set_state(SMATCH_EXTRA
, var_name
, sym
, extra_state
);
239 merge_slist(&final_states
, __fake_cur_slist
);
240 free_slist(&__fake_cur_slist
);
241 } END_FOR_EACH_PTR(tmp
);
244 FOR_EACH_PTR(final_states
, sm
) {
246 } END_FOR_EACH_PTR(sm
);
248 free_slist(&final_states
);
250 free_string(var_name
);
253 void function_comparison(int comparison
, struct expression
*expr
, long long value
, int left
)
255 struct call_back_list
*call_backs
;
256 struct fcall_back
*tmp
;
258 struct data_range
*value_range
;
259 struct state_list
*true_states
= NULL
;
260 struct state_list
*false_states
= NULL
;
263 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
265 fn
= expr
->fn
->symbol
->ident
->name
;
266 call_backs
= get_call_backs(expr
->fn
->symbol
->ident
->name
);
269 value_range
= alloc_range(value
, value
);
272 /* set true states */
273 FOR_EACH_PTR(call_backs
, tmp
) {
274 if (tmp
->type
!= RANGED_CALL
)
276 if (!true_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
278 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
279 merge_slist(&true_states
, __fake_cur_slist
);
280 free_slist(&__fake_cur_slist
);
281 } END_FOR_EACH_PTR(tmp
);
283 /* set false states */
284 FOR_EACH_PTR(call_backs
, tmp
) {
285 if (tmp
->type
!= RANGED_CALL
)
287 if (!false_comparison_range_lr(comparison
, tmp
->range
, value_range
, left
))
289 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
290 merge_slist(&false_states
, __fake_cur_slist
);
291 free_slist(&__fake_cur_slist
);
292 } END_FOR_EACH_PTR(tmp
);
295 FOR_EACH_PTR(true_states
, sm
) {
296 __set_true_false_sm(sm
, NULL
);
297 } END_FOR_EACH_PTR(sm
);
298 FOR_EACH_PTR(false_states
, sm
) {
299 __set_true_false_sm(NULL
, sm
);
300 } END_FOR_EACH_PTR(sm
);
302 if (true_states
&& !false_states
)
303 sm_msg("warning: unhandled false condition.");
304 if (!true_states
&& false_states
)
305 sm_msg("warning: unhandled true condition.");
306 free_slist(&true_states
);
307 free_slist(&false_states
);
310 void __match_initializer_call(struct symbol
*sym
)
312 struct call_back_list
*call_backs
;
313 struct expression
*initializer
= sym
->initializer
;
314 struct expression
*e_assign
, *e_symbol
;
317 if (initializer
->fn
->type
!= EXPR_SYMBOL
318 || !initializer
->fn
->symbol
)
320 fn
= initializer
->fn
->symbol
->ident
->name
;
321 call_backs
= get_call_backs(fn
);
325 e_assign
= alloc_expression(initializer
->pos
, EXPR_ASSIGNMENT
);
326 e_symbol
= alloc_expression(initializer
->pos
, EXPR_SYMBOL
);
327 e_symbol
->symbol
= sym
;
328 e_symbol
->symbol_name
= sym
->ident
;
329 e_assign
->left
= e_symbol
;
330 e_assign
->right
= initializer
;
331 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, e_assign
);
332 assign_condition_funcs(fn
, e_assign
, call_backs
);
333 assign_ranged_funcs(fn
, e_assign
, call_backs
);
336 static void match_assign_call(struct expression
*expr
)
338 struct call_back_list
*call_backs
;
340 struct expression
*right
;
342 right
= strip_expr(expr
->right
);
343 if (right
->fn
->type
!= EXPR_SYMBOL
|| !right
->fn
->symbol
)
345 fn
= right
->fn
->symbol
->ident
->name
;
346 call_backs
= get_call_backs(fn
);
349 call_call_backs(call_backs
, ASSIGN_CALL
, fn
, expr
);
350 assign_condition_funcs(fn
, expr
, call_backs
);
351 assign_ranged_funcs(fn
, expr
, call_backs
);
354 static void match_conditional_call(struct expression
*expr
)
356 struct call_back_list
*call_backs
;
357 struct fcall_back
*tmp
;
361 expr
= strip_expr(expr
);
362 if (expr
->type
!= EXPR_CALL
)
365 if (expr
->fn
->type
!= EXPR_SYMBOL
|| !expr
->fn
->symbol
)
368 fn
= expr
->fn
->symbol
->ident
->name
;
369 call_backs
= get_call_backs(fn
);
372 __fake_conditions
= 1;
373 FOR_EACH_PTR(call_backs
, tmp
) {
374 if (tmp
->type
!= CONDITIONAL_CALL
)
377 (tmp
->call_back
)(fn
, expr
, tmp
->info
);
379 FOR_EACH_PTR(__fake_cond_true
, sm
) {
380 __set_true_false_sm(sm
, NULL
);
381 } END_FOR_EACH_PTR(sm
);
382 free_slist(&__fake_cond_true
);
384 FOR_EACH_PTR(__fake_cond_false
, sm
) {
385 __set_true_false_sm(NULL
, sm
);
386 } END_FOR_EACH_PTR(sm
);
387 free_slist(&__fake_cond_false
);
389 } END_FOR_EACH_PTR(tmp
);
390 __fake_conditions
= 0;
393 void create_function_hash(void)
395 hcreate_r(10000, &func_hash
); // Apparently 1000 is too few...
398 void register_function_hooks(int id
)
400 add_hook(&match_function_call
, FUNCTION_CALL_HOOK
);
401 add_hook(&match_assign_call
, CALL_ASSIGNMENT_HOOK
);
402 add_hook(&match_conditional_call
, CONDITION_HOOK
);