extra: handle merging NULL pointers better
[smatch.git] / smatch_modification_hooks.c
blobf39c3b9ec729c91a6e52e860e18aa636cc235247
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 match_none = 0,
39 match_exact,
40 match_indirect
43 static modification_hook **hooks;
44 static modification_hook **indirect_hooks; /* parent struct modified etc */
46 void add_modification_hook(int owner, modification_hook *call_back)
48 hooks[owner] = call_back;
51 void add_indirect_modification_hook(int owner, modification_hook *call_back)
53 indirect_hooks[owner] = call_back;
56 static int matches(char *name, struct symbol *sym, struct sm_state *sm)
58 int len;
60 if (sym != sm->sym)
61 return match_none;
63 len = strlen(name);
64 if (strncmp(sm->name, name, len) == 0) {
65 if (sm->name[len] == '\0')
66 return match_exact;
67 if (sm->name[len] == '-' || sm->name[len] == '.')
68 return match_indirect;
70 if (sm->name[0] != '*')
71 return match_none;
72 if (strncmp(sm->name + 1, name, len) == 0) {
73 if (sm->name[len + 1] == '\0')
74 return match_indirect;
75 if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
76 return match_indirect;
78 return match_none;
81 static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr)
83 struct stree *stree;
84 struct sm_state *sm;
85 int match;
87 stree = __get_cur_stree();
89 FOR_EACH_SM(stree, sm) {
90 if (sm->owner > num_checks)
91 continue;
92 match = matches(name, sym, sm);
94 if (match && hooks[sm->owner])
95 (hooks[sm->owner])(sm, mod_expr);
97 if (match == match_indirect && indirect_hooks[sm->owner])
98 (indirect_hooks[sm->owner])(sm, mod_expr);
99 } END_FOR_EACH_SM(sm);
102 static void call_modification_hooks(struct expression *expr, struct expression *mod_expr)
104 char *name;
105 struct symbol *sym;
107 name = expr_to_var_sym(expr, &sym);
108 if (!name || !sym)
109 goto free;
110 call_modification_hooks_name_sym(name, sym, mod_expr);
111 free:
112 free_string(name);
115 static void db_param_add(struct expression *expr, int param, char *key, char *value)
117 struct expression *arg;
118 char *name;
119 struct symbol *sym;
121 while (expr->type == EXPR_ASSIGNMENT)
122 expr = strip_expr(expr->right);
123 if (expr->type != EXPR_CALL)
124 return;
126 arg = get_argument_from_call_expr(expr->args, param);
127 if (!arg)
128 return;
130 name = get_variable_from_key(arg, key, &sym);
131 if (!name || !sym)
132 goto free;
134 call_modification_hooks_name_sym(name, sym, expr);
135 free:
136 free_string(name);
139 static void match_assign(struct expression *expr)
141 call_modification_hooks(expr->left, expr);
144 static void unop_expr(struct expression *expr)
146 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
147 return;
149 call_modification_hooks(expr->unop, expr);
152 static void match_call(struct expression *expr)
154 struct expression *arg, *tmp;
156 FOR_EACH_PTR(expr->args, arg) {
157 tmp = strip_expr(arg);
158 if (tmp->type == EXPR_PREOP && tmp->op == '&')
159 call_modification_hooks(tmp->unop, expr);
160 else if (option_no_db)
161 call_modification_hooks(deref_expression(tmp), expr);
162 } END_FOR_EACH_PTR(arg);
165 static void asm_expr(struct statement *stmt)
167 struct expression *expr;
168 int state = 0;
170 FOR_EACH_PTR(stmt->asm_outputs, expr) {
171 switch (state) {
172 case 0: /* identifier */
173 case 1: /* constraint */
174 state++;
175 continue;
176 case 2: /* expression */
177 state = 0;
178 call_modification_hooks(expr, NULL);
179 continue;
181 } END_FOR_EACH_PTR(expr);
184 void register_modification_hooks(int id)
186 hooks = malloc((num_checks + 1) * sizeof(*hooks));
187 memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
188 indirect_hooks = malloc((num_checks + 1) * sizeof(*hooks));
189 memset(indirect_hooks, 0, (num_checks + 1) * sizeof(*hooks));
191 add_hook(&match_assign, ASSIGNMENT_HOOK);
192 add_hook(&unop_expr, OP_HOOK);
193 add_hook(&asm_expr, ASM_HOOK);
196 void register_modification_hooks_late(int id)
198 add_hook(&match_call, FUNCTION_CALL_HOOK);
199 select_return_states_hook(ADDED_VALUE, &db_param_add);