refcount: partial increments count as increments
[smatch.git] / smatch_modification_hooks.c
blob9a5d7d950bbd6e1750fa0c1caf84a7e94eb9acf6
1 /*
2 * Copyright (C) 2009 Dan Carpenter.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * There are a number of ways that variables are modified:
20 * 1) assignment
21 * 2) increment/decrement
22 * 3) assembly
23 * 4) inside functions.
25 * For setting stuff inside a function then, of course, it's more accurate if
26 * you have the cross function database built. Otherwise we are super
27 * aggressive about marking things as modified and if you have "frob(foo);" then
28 * we assume "foo->bar" is modified.
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include "smatch.h"
34 #include "smatch_extra.h"
35 #include "smatch_slist.h"
37 enum {
38 EARLY = 0,
39 LATE = 1,
40 BOTH = 2
43 static sm_hook **hooks;
44 static sm_hook **hooks_late;
46 ALLOCATOR(modification_data, "modification data");
48 static int my_id;
49 static struct smatch_state *alloc_my_state(struct expression *expr, struct smatch_state *prev)
51 struct smatch_state *state;
52 struct modification_data *data;
53 char *name;
55 expr = strip_expr(expr);
56 name = expr_to_str(expr);
57 if (!name)
58 return NULL;
60 state = __alloc_smatch_state(0);
61 state->name = alloc_sname(name);
62 free_string(name);
64 data = __alloc_modification_data(0);
65 data->prev = prev;
66 data->cur = expr;
67 state->data = data;
69 return state;
72 void add_modification_hook(int owner, sm_hook *call_back)
74 if (hooks[owner])
75 sm_fatal("multiple modification hooks for %s", check_name(owner));
76 hooks[owner] = call_back;
79 void add_modification_hook_late(int owner, sm_hook *call_back)
81 if (hooks_late[owner])
82 sm_fatal("multiple late modification hooks for %s", check_name(owner));
83 hooks_late[owner] = call_back;
86 static int shared_cnt(const char *one, const char *two)
88 int c = 0;
90 while (one[c] && two[c] && one[c] == two[c])
91 c++;
92 return c;
95 bool is_sub_member(const char *name, struct symbol *sym, struct sm_state *sm)
97 const char *sm_name;
98 int len;
100 if (sym != sm->sym)
101 return false;
103 sm_name = sm->name;
104 if (sm_name[0] == '&')
105 sm_name++;
107 len = shared_cnt(sm_name, name);
108 if (name[len] == '\0') {
109 if (sm_name[len] == '\0')
110 return true;
111 if (sm_name[len] == '-' || sm_name[len] == '.')
112 return true;
114 if (sm_name[0] != '*')
115 return false;
116 if (strncmp(sm_name + 1, name, len) == 0) {
117 if (sm_name[len + 1] == '\0')
118 return true;
119 if (sm_name[len + 1] == '-' || sm_name[len + 1] == '.')
120 return true;
122 return false;
125 static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr, int late)
127 struct sm_state *sm;
128 struct smatch_state *prev;
129 int match;
131 prev = get_state(my_id, name, sym);
133 if (cur_func_sym && !__in_fake_assign)
134 set_state(my_id, name, sym, alloc_my_state(mod_expr, prev));
136 FOR_EACH_SM_SAFE(__get_cur_stree(), sm) {
137 if (sm->owner > num_checks)
138 continue;
139 if (!hooks[sm->owner] && !hooks_late[sm->owner])
140 continue;
141 match = is_sub_member(name, sym, sm);
142 if (!match)
143 continue;
145 if (late == EARLY || late == BOTH) {
146 if (hooks[sm->owner])
147 (hooks[sm->owner])(sm, mod_expr);
149 if (late == LATE || late == BOTH) {
150 if (hooks_late[sm->owner])
151 (hooks_late[sm->owner])(sm, mod_expr);
153 } END_FOR_EACH_SM_SAFE(sm);
156 static void call_modification_hooks(struct expression *expr, struct expression *mod_expr, int late)
158 char *name;
159 struct symbol *sym;
161 name = expr_to_known_chunk_sym(expr, &sym);
162 if (!name)
163 goto free;
164 call_modification_hooks_name_sym(name, sym, mod_expr, late);
165 free:
166 free_string(name);
169 static void db_param_add(struct expression *expr, int param, char *key, char *value)
171 struct expression *arg;
172 char *name, *other_name;
173 struct symbol *sym, *other_sym;
175 while (expr->type == EXPR_ASSIGNMENT)
176 expr = strip_expr(expr->right);
177 if (expr->type != EXPR_CALL)
178 return;
180 arg = get_argument_from_call_expr(expr->args, param);
181 if (!arg)
182 return;
184 name = get_variable_from_key(arg, key, &sym);
185 if (!name || !sym)
186 goto free;
188 __in_fake_assign++;
189 call_modification_hooks_name_sym(name, sym, expr, BOTH);
190 __in_fake_assign--;
192 other_name = get_other_name_sym(name, sym, &other_sym);
193 if (other_name) {
194 __in_fake_assign++;
195 call_modification_hooks_name_sym(other_name, other_sym, expr, BOTH);
196 __in_fake_assign--;
197 free_string(other_name);
200 free:
201 free_string(name);
204 static void match_assign(struct expression *expr, int late)
206 if (__in_fake_parameter_assign)
207 return;
208 if (expr->left->smatch_flags & Fake)
209 return;
210 call_modification_hooks(expr->left, expr, late);
213 static void unop_expr(struct expression *expr, int late)
215 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
216 return;
218 call_modification_hooks(expr->unop, expr, late);
221 static void match_call(struct expression *expr)
223 struct expression *arg, *tmp;
225 /* If we have the DB then trust the DB */
226 if (!option_no_db)
227 return;
229 FOR_EACH_PTR(expr->args, arg) {
230 tmp = strip_expr(arg);
231 if (tmp->type == EXPR_PREOP && tmp->op == '&')
232 call_modification_hooks(tmp->unop, expr, BOTH);
233 else
234 call_modification_hooks(deref_expression(tmp), expr, BOTH);
235 } END_FOR_EACH_PTR(arg);
238 static void asm_expr(struct statement *stmt, int late)
240 struct asm_operand *op;
242 FOR_EACH_PTR(stmt->asm_outputs, op) {
243 call_modification_hooks(op->expr, NULL, late);
244 } END_FOR_EACH_PTR(op);
247 static void match_assign_early(struct expression *expr)
249 match_assign(expr, EARLY);
252 static void unop_expr_early(struct expression *expr)
254 unop_expr(expr, EARLY);
257 static void asm_expr_early(struct statement *stmt)
259 asm_expr(stmt, EARLY);
262 static void match_assign_late(struct expression *expr)
264 match_assign(expr, LATE);
267 static void unop_expr_late(struct expression *expr)
269 unop_expr(expr, LATE);
272 static void asm_expr_late(struct statement *stmt)
274 asm_expr(stmt, LATE);
277 struct smatch_state *get_modification_state(struct expression *expr)
279 return get_state_expr(my_id, expr);
282 void allocate_modification_hooks(void)
284 hooks = malloc(num_checks * sizeof(*hooks));
285 memset(hooks, 0, num_checks * sizeof(*hooks));
286 hooks_late = malloc(num_checks * sizeof(*hooks));
287 memset(hooks_late, 0, num_checks * sizeof(*hooks));
290 void register_modification_hooks(int id)
292 my_id = id;
294 set_dynamic_states(my_id);
296 add_hook(&match_assign_early, ASSIGNMENT_HOOK);
297 add_hook(&unop_expr_early, OP_HOOK);
298 add_hook(&asm_expr_early, ASM_HOOK);
301 void register_modification_hooks_late(int id)
303 add_hook(&match_call, FUNCTION_CALL_HOOK);
305 select_return_states_hook(PARAM_ADD, &db_param_add);
306 select_return_states_hook(PARAM_SET, &db_param_add);
308 add_hook(&match_assign_late, ASSIGNMENT_HOOK_AFTER);
309 add_hook(&unop_expr_late, OP_HOOK);
310 add_hook(&asm_expr_late, ASM_HOOK);