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:
21 * 2) increment/decrement
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.
34 #include "smatch_extra.h"
35 #include "smatch_slist.h"
43 static sm_hook
**hooks
;
44 static sm_hook
**hooks_late
;
46 ALLOCATOR(modification_data
, "modification data");
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
;
55 expr
= strip_expr(expr
);
56 name
= expr_to_str(expr
);
60 state
= __alloc_smatch_state(0);
61 state
->name
= alloc_sname(name
);
64 data
= __alloc_modification_data(0);
72 void add_modification_hook(int owner
, sm_hook
*call_back
)
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
)
90 while (one
[c
] && two
[c
] && one
[c
] == two
[c
])
95 bool is_sub_member(const char *name
, struct symbol
*sym
, struct sm_state
*sm
)
104 if (sm_name
[0] == '&')
107 len
= shared_cnt(sm_name
, name
);
108 if (name
[len
] == '\0') {
109 if (sm_name
[len
] == '\0')
111 if (sm_name
[len
] == '-' || sm_name
[len
] == '.')
114 if (sm_name
[0] != '*')
116 if (strncmp(sm_name
+ 1, name
, len
) == 0) {
117 if (sm_name
[len
+ 1] == '\0')
119 if (sm_name
[len
+ 1] == '-' || sm_name
[len
+ 1] == '.')
125 static void call_modification_hooks_name_sym(char *name
, struct symbol
*sym
, struct expression
*mod_expr
, int late
)
128 struct smatch_state
*prev
;
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
)
139 if (!hooks
[sm
->owner
] && !hooks_late
[sm
->owner
])
141 match
= is_sub_member(name
, sym
, sm
);
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
)
161 name
= expr_to_known_chunk_sym(expr
, &sym
);
164 call_modification_hooks_name_sym(name
, sym
, mod_expr
, late
);
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
)
180 arg
= get_argument_from_call_expr(expr
->args
, param
);
184 name
= get_variable_from_key(arg
, key
, &sym
);
189 call_modification_hooks_name_sym(name
, sym
, expr
, BOTH
);
192 other_name
= get_other_name_sym(name
, sym
, &other_sym
);
195 call_modification_hooks_name_sym(other_name
, other_sym
, expr
, BOTH
);
197 free_string(other_name
);
204 static void match_assign(struct expression
*expr
, int late
)
206 if (__in_fake_parameter_assign
)
208 if (expr
->left
->smatch_flags
& Fake
)
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
)
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 */
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
);
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
)
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
);