param_key: fix container of when no struct member is referenced
[smatch.git] / smatch_mtag_data.c
blob7cb2c101787525cafea603f9f19b64d06ecdaaef
1 /*
2 * Copyright (C) 2016 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 * What we're doing here is saving all the possible values for static variables.
20 * Later on we might do globals as well.
24 #include "smatch.h"
25 #include "smatch_slist.h"
26 #include "smatch_extra.h"
28 static int my_id;
29 static struct stree *vals;
31 static int save_rl(void *_rl, int argc, char **argv, char **azColName)
33 unsigned long *rl = _rl;
35 *rl = strtoul(argv[0], NULL, 10);
36 return 0;
39 static struct range_list *select_orig(mtag_t tag, int offset)
41 struct range_list *rl = NULL;
43 mem_sql(&save_rl, &rl, "select value from mtag_data where tag = %lld and offset = %d;",
44 tag, offset);
45 return rl;
48 static int is_kernel_param(const char *name)
50 struct sm_state *tmp;
51 char buf[256];
54 * I'm ignoring these because otherwise Smatch thinks that kernel
55 * parameters are always set to the default.
59 if (option_project != PROJ_KERNEL)
60 return 0;
62 snprintf(buf, sizeof(buf), "__param_%s.arg", name);
64 FOR_EACH_SM(vals, tmp) {
65 if (strcmp(tmp->name, buf) == 0)
66 return 1;
67 } END_FOR_EACH_SM(tmp);
69 return 0;
72 static bool is_ignored_macro(struct expression *expr)
74 char *macro;
76 macro = get_macro_name(expr->pos);
77 if (!macro)
78 return false;
79 if (strcmp(macro, "EXPORT_SYMBOL") == 0)
80 return true;
81 return false;
84 static bool is_head_next(struct expression *expr)
86 struct symbol *type;
88 /* Smatch thinks head->next == head is always true. *sad face* */
90 if (option_project != PROJ_KERNEL)
91 return false;
93 if (expr->type != EXPR_DEREF)
94 return false;
95 if (!expr->member || !expr->member->name ||
96 strcmp(expr->member->name, "next") != 0)
97 return false;
99 type = get_type(expr->deref);
100 if (!type)
101 return false;
102 if (type->type == SYM_PTR)
103 type = get_real_base_type(type);
104 if (type->type != SYM_STRUCT)
105 return false;
106 if (!type->ident || !type->ident->name ||
107 strcmp(type->ident->name, "list_head") != 0)
108 return false;
109 return true;
112 mtag_t ignored_mtag;
113 static bool is_ignored_tag(mtag_t tag)
115 if (tag == ignored_mtag)
116 return true;
117 return false;
120 static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl)
122 if (in_fake_env)
123 return;
124 if (is_ignored_tag(tag))
125 return;
127 rl = clone_rl_permanent(rl);
129 mem_sql(NULL, NULL, "delete from mtag_data where tag = %lld and offset = %d and type = %d",
130 tag, offset, DATA_VALUE);
131 mem_sql(NULL, NULL, "insert into mtag_data values (%lld, %d, %d, '%lu');",
132 tag, offset, DATA_VALUE, (unsigned long)rl);
135 static bool invalid_type(struct symbol *type)
137 if (!type)
138 return true;
139 if (type == &void_ctype)
140 return true;
141 if (type->type == SYM_STRUCT ||
142 type->type == SYM_ARRAY ||
143 type->type == SYM_UNION)
144 return true;
145 return false;
148 static bool parent_is_fresh_alloc(struct expression *expr)
150 struct symbol *sym;
152 sym = expr_to_sym(expr);
153 if (!sym || !sym->ident)
154 return false;
155 return is_fresh_alloc_var_sym(sym->ident->name, sym);
158 void update_mtag_data(struct expression *expr, struct smatch_state *state)
160 struct range_list *orig, *new;
161 struct symbol *type;
162 char *name;
163 mtag_t tag;
164 int offset;
166 if (!expr)
167 return;
168 if (is_ignored_macro(expr))
169 return;
170 if (is_head_next(expr))
171 return;
172 name = expr_to_var(expr);
173 if (is_kernel_param(name)) {
174 free_string(name);
175 return;
177 free_string(name);
179 if (!expr_to_mtag_offset(expr, &tag, &offset))
180 return;
182 type = get_type(expr);
183 if (offset == 0 && invalid_type(type))
184 return;
186 if (parent_is_fresh_alloc(expr))
187 orig = NULL;
188 else
189 orig = select_orig(tag, offset);
190 new = rl_union(orig, estate_rl(state));
191 insert_mtag_data(tag, offset, new);
194 static void match_global_assign(struct expression *expr)
196 struct range_list *rl;
197 mtag_t tag;
198 int offset;
199 char *name;
201 if (is_ignored_macro(expr))
202 return;
203 if (is_head_next(expr->left))
204 return;
205 name = expr_to_var(expr->left);
206 if (is_kernel_param(name)) {
207 free_string(name);
208 return;
210 free_string(name);
212 if (!expr_to_mtag_offset(expr->left, &tag, &offset))
213 return;
215 get_absolute_rl(expr->right, &rl);
216 insert_mtag_data(tag, offset, rl);
219 static int save_mtag_data(void *_unused, int argc, char **argv, char **azColName)
221 struct range_list *rl;
223 if (argc != 4) {
224 sm_msg("Error saving mtag data");
225 return 0;
227 if (!option_info)
228 return 0;
230 rl = (struct range_list *)strtoul(argv[3], NULL, 10);
231 sm_msg("SQL: insert or ignore into mtag_data values ('%s', '%s', '%s', '%s');",
232 argv[0], argv[1], argv[2], show_rl(rl));
234 return 0;
237 static void match_end_file(struct symbol_list *sym_list)
239 mem_sql(&save_mtag_data, NULL, "select * from mtag_data where type = %d;",
240 DATA_VALUE);
243 struct db_info {
244 struct symbol *type;
245 struct range_list *rl;
248 static int get_vals(void *_db_info, int argc, char **argv, char **azColName)
250 struct db_info *db_info = _db_info;
251 struct range_list *tmp;
253 str_to_rl(db_info->type, argv[0], &tmp);
254 if (db_info->rl)
255 db_info->rl = rl_union(db_info->rl, tmp);
256 else
257 db_info->rl = tmp;
259 return 0;
262 struct db_cache_results {
263 mtag_t tag;
264 struct range_list *rl;
266 static struct db_cache_results cached_results[8];
268 static int get_rl_from_mtag_offset(mtag_t tag, int offset, struct symbol *type, struct range_list **rl)
270 struct db_info db_info = {};
271 mtag_t merged = tag | offset;
272 struct range_list *mem_rl;
273 static int idx;
274 int i;
276 *rl = NULL;
278 for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
279 if (merged == cached_results[i].tag) {
280 if (cached_results[i].rl) {
281 *rl = cached_results[i].rl;
282 return 1;
284 return 0;
288 mem_rl = select_orig(tag, offset);
289 if (is_whole_rl(mem_rl))
290 goto update_cache;
292 db_info.type = type;
293 run_sql(get_vals, &db_info,
294 "select value from mtag_data where tag = %lld and offset = %d and type = %d;",
295 tag, offset, DATA_VALUE);
296 if (!db_info.rl)
297 goto update_cache;
298 db_info.rl = rl_union(mem_rl, db_info.rl);
299 if (is_whole_rl(db_info.rl))
300 goto update_cache;
302 *rl = db_info.rl;
304 update_cache:
305 cached_results[idx].tag = merged;
306 cached_results[idx].rl = *rl;
307 idx = (idx + 1) % ARRAY_SIZE(cached_results);
309 return !!*rl;
312 static void clear_cache(struct symbol *sym)
314 memset(cached_results, 0, sizeof(cached_results));
317 int get_mtag_rl(struct expression *expr, struct range_list **rl)
319 struct symbol *type;
320 mtag_t tag;
321 int offset;
323 if (is_local_variable(expr))
324 return 0;
325 if (!expr_to_mtag_offset(expr, &tag, &offset))
326 return 0;
327 if (offset >= MTAG_OFFSET_MASK)
328 return 0;
330 type = get_type(expr);
331 if (invalid_type(type))
332 return 0;
334 return get_rl_from_mtag_offset(tag, offset, type, rl);
337 void register_mtag_data(int id)
339 my_id = id;
341 ignored_mtag = str_to_mtag("extern boot_params");
342 add_hook(&clear_cache, FUNC_DEF_HOOK);
344 if (!option_info)
345 return;
346 add_hook(&match_global_assign, GLOBAL_ASSIGNMENT_HOOK);
347 add_hook(&match_end_file, END_FILE_HOOK);