constraints: escape SQL statements
[smatch.git] / smatch_param_set.c
blob21456057ceeaa14c69895f917e187632aec45828
1 /*
2 * Copyright (C) 2012 Oracle.
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 * This is for functions like:
21 * int foo(int *x)
22 * {
23 * if (*x == 42) {
24 * *x = 0;
25 * return 1;
26 * }
27 * return 0;
28 * }
30 * If we return 1 that means the value of *x has been set to 0. If we return
31 * 0 then we have left *x alone.
35 #include "scope.h"
36 #include "smatch.h"
37 #include "smatch_slist.h"
38 #include "smatch_extra.h"
40 static int my_id;
42 static struct smatch_state *unmatched_state(struct sm_state *sm)
44 return alloc_estate_empty();
47 static int parent_is_set(const char *name, struct symbol *sym, struct smatch_state *state)
49 struct expression *faked;
50 char *left_name;
51 int ret = 0;
52 int len;
54 if (!__in_fake_assign)
55 return 0;
56 if (!is_whole_rl(estate_rl(state)))
57 return 0;
58 if (get_state(my_id, name, sym))
59 return 0;
61 faked = get_faked_expression();
62 if (!faked)
63 return 0;
64 if ((faked->type == EXPR_PREOP || faked->type == EXPR_POSTOP) &&
65 (faked->op == SPECIAL_INCREMENT || faked->op == SPECIAL_DECREMENT)) {
66 faked = strip_expr(faked->unop);
67 if (faked->type == EXPR_SYMBOL)
68 return 1;
69 return 0;
71 if (faked->type != EXPR_ASSIGNMENT)
72 return 0;
74 left_name = expr_to_var(faked->left);
75 if (!left_name)
76 return 0;
78 len = strlen(left_name);
79 if (strncmp(name, left_name, len) == 0 && name[len] == '-')
80 ret = 1;
81 free_string(left_name);
83 return ret;
86 static void extra_mod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
88 if (parent_is_set(name, sym, state))
89 return;
90 if (get_param_num_from_sym(sym) < 0)
91 return;
92 set_state(my_id, name, sym, state);
96 * This function is is a dirty hack because extra_mod_hook is giving us a NULL
97 * sym instead of a vsl.
99 static void match_array_assignment(struct expression *expr)
101 struct expression *array, *offset;
102 char *name;
103 struct symbol *sym;
104 struct range_list *rl;
105 sval_t sval;
106 char buf[256];
108 if (__in_fake_assign)
109 return;
111 if (!is_array(expr->left))
112 return;
113 array = get_array_base(expr->left);
114 offset = get_array_offset(expr->left);
116 /* These are handled by extra_mod_hook() */
117 if (get_value(offset, &sval))
118 return;
119 name = expr_to_var_sym(array, &sym);
120 if (!name || !sym)
121 goto free;
122 if (get_param_num_from_sym(sym) < 0)
123 goto free;
124 get_absolute_rl(expr->right, &rl);
125 rl = cast_rl(get_type(expr->left), rl);
127 snprintf(buf, sizeof(buf), "*%s", name);
128 set_state(my_id, buf, sym, alloc_estate_rl(rl));
129 free:
130 free_string(name);
134 * This relies on the fact that these states are stored so that
135 * foo->bar is before foo->bar->baz.
137 static int parent_set(struct string_list *list, const char *name)
139 char *tmp;
140 int len;
141 int ret;
143 FOR_EACH_PTR(list, tmp) {
144 len = strlen(tmp);
145 ret = strncmp(tmp, name, len);
146 if (ret < 0)
147 continue;
148 if (ret > 0)
149 return 0;
150 if (name[len] == '-')
151 return 1;
152 } END_FOR_EACH_PTR(tmp);
154 return 0;
157 static void print_return_value_param(int return_id, char *return_ranges, struct expression *expr)
159 struct sm_state *sm;
160 struct smatch_state *extra;
161 int param;
162 struct range_list *rl;
163 const char *param_name;
164 struct string_list *set_list = NULL;
165 char *math_str;
166 char buf[256];
167 sval_t sval;
169 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
170 if (!estate_rl(sm->state))
171 continue;
172 extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
173 if (extra) {
174 rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
175 if (!rl)
176 continue;
177 } else {
178 rl = estate_rl(sm->state);
181 param = get_param_num_from_sym(sm->sym);
182 if (param < 0)
183 continue;
184 param_name = get_param_name(sm);
185 if (!param_name)
186 continue;
187 if (strcmp(param_name, "$") == 0) {
188 insert_string(&set_list, (char *)sm->name);
189 continue;
192 if (rl_to_sval(rl, &sval)) {
193 insert_string(&set_list, (char *)sm->name);
194 sql_insert_return_states(return_id, return_ranges,
195 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
196 param, param_name, show_rl(rl));
197 continue;
200 math_str = get_value_in_terms_of_parameter_math_var_sym(sm->name, sm->sym);
201 if (math_str) {
202 snprintf(buf, sizeof(buf), "%s[%s]", show_rl(rl), math_str);
203 insert_string(&set_list, (char *)sm->name);
204 sql_insert_return_states(return_id, return_ranges,
205 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
206 param, param_name, buf);
207 continue;
210 /* no useful information here. */
211 if (is_whole_rl(rl) && parent_set(set_list, sm->name))
212 continue;
213 insert_string(&set_list, (char *)sm->name);
215 sql_insert_return_states(return_id, return_ranges,
216 param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
217 param, param_name, show_rl(rl));
219 } END_FOR_EACH_SM(sm);
221 free_ptr_list((struct ptr_list **)&set_list);
224 int param_was_set_var_sym(const char *name, struct symbol *sym)
226 struct sm_state *sm;
227 int len;
229 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
230 if (sm->sym != sym)
231 continue;
232 len = strlen(sm->name);
233 if (strncmp(sm->name, name, len) != 0)
234 continue;
235 if (name[len] == '\0' ||
236 name[len] == '-')
237 return 1;
238 } END_FOR_EACH_SM(sm);
240 return 0;
243 int param_was_set(struct expression *expr)
245 char *name;
246 struct symbol *sym;
247 int ret = 0;
249 name = expr_to_var_sym(expr, &sym);
250 if (!name || !sym)
251 goto free;
253 ret = param_was_set_var_sym(name, sym);
254 free:
255 free_string(name);
256 return ret;
259 void register_param_set(int id)
261 my_id = id;
263 add_extra_mod_hook(&extra_mod_hook);
264 add_hook(match_array_assignment, ASSIGNMENT_HOOK);
265 add_unmatched_state_hook(my_id, &unmatched_state);
266 add_merge_hook(my_id, &merge_estates);
267 add_split_return_callback(&print_return_value_param);