redundant_null_check: silence some false positives
[smatch.git] / smatch_modification_hooks.c
bloba143d69b003901c84f3f707124fc74d82d1de946
1 /*
2 * sparse/smatch_modification_hooks.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * There are a number of ways that variables are modified:
12 * 1) assignment
13 * 2) increment/decrement
14 * 3) assembly
15 * 4) inside functions.
17 * For setting stuff inside a function then, of course, it's more accurate if
18 * you have the cross function database built. Otherwise we are super
19 * aggressive about marking things as modified and if you have "frob(foo);" then
20 * we assume "foo->bar" is modified.
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include "smatch.h"
26 #include "smatch_extra.h"
27 #include "smatch_slist.h"
29 enum {
30 match_none = 0,
31 match_exact,
32 match_indirect
35 static modification_hook **hooks;
36 static modification_hook **indirect_hooks; /* parent struct modified etc */
38 void add_modification_hook(int owner, modification_hook *call_back)
40 hooks[owner] = call_back;
43 void add_indirect_modification_hook(int owner, modification_hook *call_back)
45 indirect_hooks[owner] = call_back;
48 static int matches(char *name, struct symbol *sym, struct sm_state *sm)
50 int len;
52 if (sym != sm->sym)
53 return match_none;
55 len = strlen(name);
56 if (strncmp(sm->name, name, len) == 0) {
57 if (sm->name[len] == '\0')
58 return match_exact;
59 if (sm->name[len] == '-' || sm->name[len] == '.')
60 return match_indirect;
62 if (sm->name[0] != '*')
63 return match_none;
64 if (strncmp(sm->name + 1, name, len) == 0) {
65 if (sm->name[len + 1] == '\0')
66 return match_indirect;
67 if (sm->name[len + 1] == '-' || sm->name[len + 1] == '.')
68 return match_indirect;
70 return match_none;
73 static void call_modification_hooks_name_sym(char *name, struct symbol *sym, struct expression *mod_expr)
75 struct state_list *slist;
76 struct sm_state *sm;
77 int match;
79 slist = __get_cur_slist();
81 FOR_EACH_PTR(slist, sm) {
82 if (sm->owner > num_checks)
83 continue;
84 match = matches(name, sym, sm);
86 if (match && hooks[sm->owner])
87 (hooks[sm->owner])(sm, mod_expr);
89 if (match == match_indirect && indirect_hooks[sm->owner])
90 (indirect_hooks[sm->owner])(sm, mod_expr);
91 } END_FOR_EACH_PTR(sm);
94 static void call_modification_hooks(struct expression *expr, struct expression *mod_expr)
96 char *name;
97 struct symbol *sym;
99 name = expr_to_var_sym(expr, &sym);
100 if (!name || !sym)
101 goto free;
102 call_modification_hooks_name_sym(name, sym, mod_expr);
103 free:
104 free_string(name);
107 static void db_param_add(struct expression *expr, int param, char *key, char *value)
109 struct expression *arg;
110 char *name;
111 struct symbol *sym;
113 while (expr->type == EXPR_ASSIGNMENT)
114 expr = strip_expr(expr->right);
115 if (expr->type != EXPR_CALL)
116 return;
118 arg = get_argument_from_call_expr(expr->args, param);
119 if (!arg)
120 return;
122 name = get_variable_from_key(arg, key, &sym);
123 if (!name || !sym)
124 goto free;
126 call_modification_hooks_name_sym(name, sym, expr);
127 free:
128 free_string(name);
131 static void match_assign(struct expression *expr)
133 call_modification_hooks(expr->left, expr);
136 static void unop_expr(struct expression *expr)
138 if (expr->op != SPECIAL_DECREMENT && expr->op != SPECIAL_INCREMENT)
139 return;
141 call_modification_hooks(expr->unop, expr);
144 static void match_call(struct expression *expr)
146 struct expression *arg, *tmp;
148 FOR_EACH_PTR(expr->args, arg) {
149 tmp = strip_expr(arg);
150 if (tmp->type == EXPR_PREOP && tmp->op == '&')
151 call_modification_hooks(tmp->unop, expr);
152 else if (option_no_db)
153 call_modification_hooks(deref_expression(tmp), expr);
154 } END_FOR_EACH_PTR(arg);
157 static void asm_expr(struct statement *stmt)
159 struct expression *expr;
160 int state = 0;
162 FOR_EACH_PTR(stmt->asm_outputs, expr) {
163 switch (state) {
164 case 0: /* identifier */
165 case 1: /* constraint */
166 state++;
167 continue;
168 case 2: /* expression */
169 state = 0;
170 call_modification_hooks(expr, NULL);
171 continue;
173 } END_FOR_EACH_PTR(expr);
176 void register_modification_hooks(int id)
178 hooks = malloc((num_checks + 1) * sizeof(*hooks));
179 memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
180 indirect_hooks = malloc((num_checks + 1) * sizeof(*hooks));
181 memset(indirect_hooks, 0, (num_checks + 1) * sizeof(*hooks));
183 add_hook(&match_assign, ASSIGNMENT_HOOK);
184 add_hook(&unop_expr, OP_HOOK);
185 add_hook(&asm_expr, ASM_HOOK);
188 void register_modification_hooks_late(int id)
190 add_hook(&match_call, FUNCTION_CALL_HOOK);
191 select_return_states_hook(ADDED_VALUE, &db_param_add);