*new* smatch_scripts/summarize_errs.sh: script for iterating through a list of errors
[smatch.git] / smatch_function_hooks.c
blob87a90c2212afb8ef10db206c73d962e74b50dbdc
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 *final_states = NULL;
141 struct range_list *handled_ranges = NULL;
142 struct call_back_list *same_range_call_backs = NULL;
144 var_name = get_variable_from_expr(expr->left, &sym);
145 if (!var_name || !sym)
146 goto free;
148 __fake_cur = 1;
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 tack_on(&handled_ranges, tmp->range);
156 same_range_call_backs = get_same_ranged_call_backs(call_backs, tmp->range);
157 call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
158 __free_ptr_list((struct ptr_list **)&same_range_call_backs);
160 extra_state = alloc_extra_state_range(tmp->range->min, tmp->range->max);
161 set_state(SMATCH_EXTRA, var_name, sym, extra_state);
163 merge_slist(&final_states, __fake_cur_slist);
164 free_slist(&__fake_cur_slist);
165 } END_FOR_EACH_PTR(tmp);
166 __fake_cur = 0;
168 FOR_EACH_PTR(final_states, sm) {
169 __set_state(sm);
170 } END_FOR_EACH_PTR(sm);
172 free_slist(&final_states);
173 free:
174 free_string(var_name);
177 void function_comparison(int comparison, struct expression *expr, long long value, int left)
179 struct call_back_list *call_backs;
180 struct fcall_back *tmp;
181 const char *fn;
182 struct data_range *value_range;
183 struct state_list *true_states = NULL;
184 struct state_list *false_states = NULL;
185 struct sm_state *sm;
187 if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol)
188 return;
189 fn = expr->fn->symbol->ident->name;
190 call_backs = search_callback(func_hash, (char *)expr->fn->symbol->ident->name);
191 if (!call_backs)
192 return;
193 value_range = alloc_range(value, value);
195 __fake_cur = 1;
196 /* set true states */
197 FOR_EACH_PTR(call_backs, tmp) {
198 if (tmp->type != RANGED_CALL)
199 continue;
200 if (!true_comparison_range_lr(comparison, tmp->range, value_range, left))
201 continue;
202 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
203 } END_FOR_EACH_PTR(tmp);
204 merge_slist(&true_states, __fake_cur_slist);
205 free_slist(&__fake_cur_slist);
207 /* set false states */
208 FOR_EACH_PTR(call_backs, tmp) {
209 if (tmp->type != RANGED_CALL)
210 continue;
211 if (!false_comparison_range_lr(comparison, tmp->range, value_range, left))
212 continue;
213 ((implication_hook *)(tmp->call_back))(fn, expr, NULL, tmp->info);
214 } END_FOR_EACH_PTR(tmp);
215 merge_slist(&false_states, __fake_cur_slist);
216 free_slist(&__fake_cur_slist);
217 __fake_cur = 0;
219 FOR_EACH_PTR(true_states, sm) {
220 __set_true_false_sm(sm, NULL);
221 } END_FOR_EACH_PTR(sm);
222 FOR_EACH_PTR(false_states, sm) {
223 __set_true_false_sm(NULL, sm);
224 } END_FOR_EACH_PTR(sm);
226 if (true_states && !false_states)
227 sm_msg("warning: unhandled false condition.");
228 if (!true_states && false_states)
229 sm_msg("warning: unhandled true condition.");
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);