comparison: handle preops like "if (++a == b)"
[smatch.git] / smatch_local_values.c
blobe1a0de170d472fd723e0651f36025b4238b16105
1 /*
2 * Copyright (C) 2013 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
18 #include "scope.h"
19 #include "smatch.h"
20 #include "smatch_slist.h"
21 #include "smatch_extra.h"
23 static int my_id;
26 * I'm going to store the states of local data at the end of each function.
27 * Then at the end of the file, I'll combine the possible range lists for
28 * each state and store the value in the on-disk database.
30 * One issue is that when I read the data back from the in-memory database at
31 * the end of the file, then I don't have access to type information. I'll just
32 * cast everything to "long long" for now, I guess. We'll see how that works.
35 static char *db_vals;
36 static int get_vals(void *unused, int argc, char **argv, char **azColName)
38 db_vals = alloc_string(argv[0]);
39 return 0;
42 int get_local_rl(struct expression *expr, struct range_list **rl)
44 char *name;
45 struct range_list *tmp;
47 if (!is_static(expr))
48 return 0;
49 name = expr_to_var(expr);
50 if (!name)
51 return 0;
53 db_vals = NULL;
54 run_sql(get_vals, NULL,
55 "select value from local_values where file = '%s' and variable = '%s';",
56 get_filename(), name);
57 free_string(name);
58 if (!db_vals)
59 return 0;
60 str_to_rl(&llong_ctype, db_vals, &tmp);
61 *rl = cast_rl(get_type(expr), tmp);
62 free_string(db_vals);
64 return 1;
67 int get_local_max_helper(struct expression *expr, sval_t *sval)
69 struct range_list *rl;
71 if (!get_local_rl(expr, &rl))
72 return 0;
73 *sval = rl_max(rl);
74 return 1;
77 int get_local_min_helper(struct expression *expr, sval_t *sval)
79 struct range_list *rl;
81 if (!get_local_rl(expr, &rl))
82 return 0;
83 *sval = rl_min(rl);
84 return 1;
87 static struct smatch_state *unmatched_state(struct sm_state *sm)
89 return alloc_estate_empty();
92 static void extra_mod_hook(const char *name, struct symbol *sym, struct smatch_state *state)
94 struct smatch_state *old;
95 struct smatch_state *new;
97 if (!sym || !(sym->ctype.modifiers & MOD_STATIC))
98 return;
99 old = get_state(my_id, name, sym);
100 if (old)
101 new = merge_estates(old, state);
102 else
103 new = state;
104 set_state(my_id, name, sym, new);
107 static void process_states(struct stree *stree)
109 struct sm_state *sm;
110 struct smatch_state *extra;
111 struct range_list *rl;
113 FOR_EACH_SM(stree, sm) {
114 if (sm->owner != my_id)
115 continue;
116 extra = get_state_stree(stree, SMATCH_EXTRA, sm->name, sm->sym);
117 if (extra && estate_rl(extra))
118 rl = rl_intersection(estate_rl(sm->state), estate_rl(extra));
119 else
120 rl = estate_rl(sm->state);
121 rl = cast_rl(&llong_ctype, rl);
122 mem_sql(NULL, NULL,
123 "insert into local_values values ('%s', '%s', '%s', %lu);",
124 get_filename(), sm->name, show_rl(rl),
125 (unsigned long)sm->sym);
126 } END_FOR_EACH_SM(sm);
129 static int get_initial_value_sym(struct symbol *sym, char *name, sval_t *sval)
131 struct expression *expr_symbol, *deref, *tmp;
132 char *member_name;
134 if (!sym)
135 return 0;
137 if (!sym->initializer) {
138 *sval = sval_type_val(&llong_ctype, 0);
139 return 1;
141 if (sym->initializer->type != EXPR_INITIALIZER)
142 return get_value(sym->initializer, sval);
144 expr_symbol = symbol_expression(sym);
145 FOR_EACH_PTR(sym->initializer->expr_list, tmp) {
146 if (tmp->type != EXPR_IDENTIFIER) /* how to handle arrays?? */
147 continue;
148 deref = member_expression(expr_symbol, '.', tmp->expr_ident);
149 member_name = expr_to_var(deref);
150 if (!member_name)
151 continue;
152 if (strcmp(name, member_name) == 0) {
153 free_string(member_name);
154 return get_value(tmp->ident_expression, sval);
156 free_string(member_name);
157 } END_FOR_EACH_PTR(tmp);
159 return 0;
162 static char *cur_name;
163 static struct symbol *cur_symbol;
164 static struct range_list *cur_rl;
165 static void add_current_local(void)
167 sval_t initial;
169 if (!get_initial_value_sym(cur_symbol, cur_name, &initial)) {
170 free_string(cur_name);
171 cur_name = NULL;
172 cur_rl = NULL;
173 return;
175 add_range(&cur_rl, initial, initial);
176 if (!is_whole_rl(cur_rl))
177 sql_insert_local_values(cur_name, show_rl(cur_rl));
178 free_string(cur_name);
179 cur_name = NULL;
180 cur_rl = NULL;
183 static int save_final_values(void *unused, int argc, char **argv, char **azColName)
185 char *name = argv[0];
186 char *sym_str = argv[1];
187 char *value = argv[2];
188 struct range_list *rl;
190 if (!cur_name) {
191 cur_name = alloc_string(name);
192 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
193 } else if (strcmp(cur_name, name) != 0) {
194 add_current_local();
195 cur_name = alloc_string(name);
196 cur_symbol = (struct symbol *)strtoul(sym_str, NULL, 10);
197 cur_rl = NULL;
200 str_to_rl(&llong_ctype, value, &rl);
201 cur_rl = rl_union(cur_rl, rl);
203 return 0;
206 static void match_end_file(struct symbol_list *sym_list)
208 mem_sql(save_final_values, NULL,
209 "select distinct variable, symbol, value from local_values order by variable;");
210 if (cur_name)
211 add_current_local();
214 void register_local_values(int id)
216 my_id = id;
218 if (!option_info)
219 return;
221 add_extra_mod_hook(&extra_mod_hook);
222 add_unmatched_state_hook(my_id, &unmatched_state);
223 add_merge_hook(my_id, &merge_estates);
224 all_return_states_hook(&process_states);
225 add_hook(match_end_file, END_FILE_HOOK);
226 mem_sql(NULL, NULL, "alter table local_values add column symbol integer;");