kernel.no_return_funcs: add kunit_do_failed_assertion()
[smatch/bkmgit.git] / smatch_units.c
blob022351c004ce72c599637e6d5c669b9d495d0751
1 /*
2 * Copyright (C) 2018 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 "smatch.h"
19 #include "smatch_slist.h"
21 static int my_id;
23 GLOBAL_STATE(unit_bit);
24 GLOBAL_STATE(unit_byte);
25 GLOBAL_STATE(unit_array_size);
26 GLOBAL_STATE(unit_long);
27 GLOBAL_STATE(unit_page);
28 GLOBAL_STATE(unit_msec);
29 GLOBAL_STATE(unit_ns);
30 GLOBAL_STATE(unit_jiffy);
32 struct type_info {
33 const char *name;
34 int type;
35 int param;
36 const char *key;
37 const char *value;
40 static struct type_info func_table[] = {
41 { "unit_msecs_to_jiffies_timeout", UNITS, -1, "$", "unit_jiffy" },
42 { "round_jiffies_up_relative", UNITS, -1, "$", "unit_jiffy" },
45 static struct smatch_state *str_to_units(const char *str)
47 if (!str)
48 return NULL;
50 if (strcmp(str, "unit_bit") == 0)
51 return &unit_bit;
52 if (strcmp(str, "unit_byte") == 0)
53 return &unit_byte;
54 if (strcmp(str, "unit_page") == 0)
55 return &unit_page;
56 if (strcmp(str, "unit_msec") == 0)
57 return &unit_msec;
58 if (strcmp(str, "unit_jiffy") == 0)
59 return &unit_jiffy;
60 if (strcmp(str, "unit_long") == 0)
61 return &unit_long;
62 if (strcmp(str, "unit_array_size") == 0)
63 return &unit_array_size;
64 if (strcmp(str, "unknown") == 0)
65 return NULL;
67 return NULL;
70 static struct smatch_state *get_units_from_type(struct expression *expr);
72 static struct smatch_state *merge_units(struct smatch_state *s1, struct smatch_state *s2)
74 if (s1 == &undefined)
75 return s2;
76 if (s2 == &undefined)
77 return s1;
78 return &merged;
81 static bool is_ignored_type(char *name)
83 if (!name)
84 return false;
85 if (strcmp(name, "(union anonymous)->__val") == 0)
86 return true;
87 if (strncmp(name, "(struct fs_parse_result)", 24) == 0)
88 return true;
89 return false;
92 static void store_type_in_db(struct expression *expr, struct smatch_state *state)
94 char *member;
96 member = get_member_name(expr);
97 if (!member)
98 return;
99 if (is_ignored_type(member))
100 return;
102 sql_insert_cache(type_info, "0x%llx, %d, '%s', '%s'", get_base_file_id(), UNITS, member, state->name);
105 static void set_units(struct expression *expr, struct smatch_state *state)
107 if (!state)
108 return;
110 set_state_expr(my_id, expr, state);
111 store_type_in_db(expr, state);
114 static bool is_PAGE_SHIFT(struct expression *expr)
116 char *macro;
118 macro = get_macro_name(expr->pos);
119 if (macro && strcmp(macro, "PAGE_SHIFT") == 0)
120 return true;
121 return false;
124 static bool is_PAGE_SIZE(struct expression *expr)
126 char *macro;
128 macro = get_macro_name(expr->pos);
129 if (macro && strcmp(macro, "PAGE_SIZE") == 0)
130 return true;
131 return false;
134 static bool is_BITS_PER_LONG(struct expression *expr)
136 char *macro;
138 macro = get_macro_name(expr->pos);
139 if (macro && strcmp(macro, "BITS_PER_LONG") == 0)
140 return true;
141 return false;
144 static struct smatch_state *binop_helper(struct expression *left, int op, struct expression *right)
146 struct smatch_state *left_state, *right_state;
147 sval_t val;
149 switch(op) {
150 case '-':
151 // subtracting pointers gives unit_byte
152 /* fall through */
153 case '+':
154 left_state = get_units(left);
155 right_state = get_units(right);
156 if (left_state == &unit_array_size ||
157 right_state == &unit_array_size)
158 return NULL;
160 return left_state ? left_state : right_state;
161 case '*':
162 /* FIXME: A multiply is almost always bytes but it can be bits. */
163 if (is_PAGE_SIZE(right))
164 return &unit_byte;
165 if (!get_implied_value(right, &val))
166 return NULL;
167 /* 4096 is almost always a unit_page -> bytes converstion */
168 if (val.value == 4096)
169 return &unit_byte;
170 return NULL;
171 case '/':
172 if (is_BITS_PER_LONG(right))
173 return &unit_long;
174 if (is_PAGE_SIZE(right))
175 return &unit_page;
176 if (!get_implied_value(right, &val))
177 return NULL;
178 if (val.value == 4096)
179 return &unit_page;
180 return NULL;
181 case SPECIAL_LEFTSHIFT:
182 if (is_PAGE_SHIFT(right))
183 return &unit_byte;
184 return NULL;
185 case SPECIAL_RIGHTSHIFT:
186 if (is_PAGE_SHIFT(right))
187 return &unit_page;
188 return NULL;
190 return NULL;
193 static struct smatch_state *get_units_binop(struct expression *expr)
195 return binop_helper(expr->left, expr->op, expr->right);
198 static struct smatch_state *get_units_call(struct expression *expr)
200 expr = strip_expr(expr);
201 if (!expr || expr->type != EXPR_CALL)
202 return NULL;
204 if (sym_name_is("unit_msecs_to_jiffies", expr->fn))
205 return &unit_jiffy;
206 if (sym_name_is("jiffies_to_unit_msecs", expr->fn))
207 return &unit_msec;
209 return NULL;
212 static int db_units(void *_units, int argc, char **argv, char **azColName)
214 char **units = _units;
216 if (*units) {
217 if (strcmp(*units, argv[0]) == 0)
218 return 0;
219 free_string(*units);
220 *units = alloc_string("unknown");
221 return 0;
224 *units = alloc_string(argv[0]);
225 return 0;
228 static struct smatch_state *get_units_from_type(struct expression *expr)
230 char *member;
231 char *units = NULL;
232 struct smatch_state *ret = NULL;
234 member = get_member_name(expr);
235 if (!member)
236 return NULL;
237 if (strcmp(member, "(struct vm_area_struct)->vm_pgoff") == 0)
238 return &unit_page;
239 cache_sql(&db_units, &units, "select value from type_info where type = %d and key = '%s';",
240 UNITS, member);
241 run_sql(&db_units, &units, "select value from type_info where type = %d and key = '%s';",
242 UNITS, member);
243 free_string(member);
244 if (!units)
245 return NULL;
247 ret = str_to_units(units);
249 free_string(units);
251 return ret;
254 struct smatch_state *get_units(struct expression *expr)
256 struct smatch_state *state;
257 char *ident;
259 expr = strip_expr(expr);
260 if (!expr)
261 return NULL;
263 if (expr->type == EXPR_PTRSIZEOF ||
264 expr->type == EXPR_SIZEOF)
265 return &unit_byte;
267 ident = pos_ident(expr->pos);
268 if (ident) {
269 if (strcmp(ident, "sizeof") == 0 ||
270 strcmp(ident, "PAGE_SIZE") == 0)
271 return &unit_byte;
272 if (strcmp(ident, "jiffies") == 0)
273 return &unit_jiffy;
274 if (strcmp(ident, "BITS_PER_LONG") == 0)
275 return &unit_bit;
276 if (strcmp(ident, "BITS_PER_LONG_LONG") == 0)
277 return &unit_bit;
278 if (strcmp(ident, "ARRAY_SIZE") == 0)
279 return &unit_array_size;
282 if (expr->type == EXPR_BINOP)
283 return get_units_binop(expr);
285 if (expr->type == EXPR_CALL)
286 return get_units_call(expr);
288 state = get_state_expr(my_id, expr);
289 if (state == &merged || state == &undefined)
290 return NULL;
291 if (state)
292 return state;
294 return get_units_from_type(expr);
297 bool is_array_size_units(struct expression *expr)
299 return get_units(expr) == &unit_array_size;
302 static void match_allocation(struct expression *expr,
303 const char *name, struct symbol *sym,
304 struct allocation_info *info)
306 struct expression *right, *left;
308 if (info->nr_elems && info->elem_size) {
309 left = info->nr_elems;
310 right = info->elem_size;
311 } else if (info->total_size &&
312 info->total_size->type == EXPR_BINOP &&
313 info->total_size->op == '*') {
314 left = strip_expr(info->total_size->left);
315 right = strip_expr(info->total_size->right);
316 } else {
317 return;
320 if (get_units(left) == &unit_byte)
321 set_units(right, &unit_array_size);
322 if (get_units(right) == &unit_byte)
323 set_units(left, &unit_array_size);
326 static void match_binop_set(struct expression *expr)
328 struct smatch_state *left, *right;
329 struct symbol *type;
331 if (expr->op == SPECIAL_LEFTSHIFT && is_PAGE_SHIFT(expr->right)) {
332 set_units(expr->left, &unit_page);
333 return;
336 if (expr->op == SPECIAL_RIGHTSHIFT && is_PAGE_SHIFT(expr->right)) {
337 set_units(expr->left, &unit_byte);
338 return;
341 if (expr->op != '+' && expr->op != '-')
342 return;
344 type = get_type(expr->left);
345 if (type && (type->type == SYM_PTR || type->type == SYM_ARRAY))
346 return;
348 left = get_units(expr->left);
349 right = get_units(expr->right);
351 if (left && !right)
352 set_units(expr->right, left);
353 if (right && !left)
354 set_units(expr->left, right);
357 static void match_condition_set(struct expression *expr)
359 struct smatch_state *left, *right;
361 if (expr->type != EXPR_COMPARE)
362 return;
364 left = get_units(expr->left);
365 right = get_units(expr->right);
367 if (left && !right)
368 set_units(expr->right, left);
369 if (right && !left)
370 set_units(expr->left, right);
373 static void match_assign(struct expression *expr)
375 struct smatch_state *state = NULL;
377 if (__in_fake_assign)
378 return;
380 switch(expr->op) {
381 case '=':
382 state = get_units(expr->right);
383 break;
384 case SPECIAL_SHR_ASSIGN:
385 case SPECIAL_SHL_ASSIGN:
386 case SPECIAL_DIV_ASSIGN:
387 case SPECIAL_MUL_ASSIGN:
388 state = binop_helper(expr->left, op_remove_assign(expr->op),
389 expr->right);
392 if (state)
393 set_units(expr->left, state);
394 // else
395 // clear_units(expr->left);
398 static void set_implied_units(struct expression *call, struct expression *arg, char *key, char *value)
400 struct smatch_state *state;
401 struct symbol *sym;
402 char *name;
404 state = str_to_units(value);
405 if (!state)
406 return;
407 name = get_variable_from_key(arg, key, &sym);
408 if (!name || !sym)
409 goto free;
410 set_state(my_id, name, sym, state);
411 free:
412 free_string(name);
415 static void set_param_units(const char *name, struct symbol *sym, char *key, char *value)
417 struct smatch_state *state;
419 state = str_to_units(value);
420 if (!state)
421 return;
422 set_state(my_id, sym->ident->name, sym, state);
425 static void set_param_units_from_table(struct expression *expr, const char *name, struct symbol *sym, void *data)
427 const char *value = data;
428 struct smatch_state *state;
430 state = str_to_units(value);
431 if (!state)
432 return;
433 set_state(my_id, name, sym, state);
436 static void match_call_info(struct expression *expr)
438 struct expression *arg;
439 struct smatch_state *state;
440 char *fn_name;
441 int param = -1;
443 if (expr->fn->type != EXPR_SYMBOL)
444 return;
445 fn_name = expr_to_var(expr->fn);
446 if (!fn_name)
447 return;
449 FOR_EACH_PTR(expr->args, arg) {
450 param++;
451 state = get_units(arg);
452 if (!state)
453 continue;
454 // sql_insert_cache(return_implies, "0x%llx, '%s', 0, %d, %d, %d, '%s', '%s'",
455 // get_base_file_id(), fn_name, is_static(expr->fn), UNITS, param, "$", state->name);
456 sql_insert_caller_info(expr, UNITS, param, "$", state->name);
458 } END_FOR_EACH_PTR(arg);
460 free_string(fn_name);
463 static void process_states(void)
465 struct symbol *arg;
466 struct smatch_state *state, *start_state;
467 int param = -1;
469 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
470 param++;
471 state = get_state(my_id, arg->ident->name, arg);
472 if (!state || state == &merged || state == &undefined)
473 continue;
474 start_state = get_state_stree(get_start_states(), my_id, arg->ident->name, arg);
475 if (state == start_state)
476 continue;
477 sql_insert_cache(return_implies, "0x%llx, '%s', 0, %d, %d, %d, '%s', '%s'",
478 get_base_file_id(), get_function(), fn_static(), UNITS, param, "$", state->name);
479 } END_FOR_EACH_PTR(arg);
482 char *get_unit_str(struct expression *expr)
484 struct smatch_state *state;
486 state = get_units(expr);
487 if (!state)
488 return NULL;
489 return (char *)state->name;
492 void register_units(int id)
494 struct type_info *info;
495 int i;
497 my_id = id;
499 for (i = 0; i < ARRAY_SIZE(func_table); i++) {
500 info = &func_table[i];
501 add_function_param_key_hook(info->name,
502 set_param_units_from_table,
503 info->param, info->key,
504 (void *)info->value);
507 add_merge_hook(my_id, &merge_units);
509 add_hook(&match_binop_set, BINOP_HOOK);
510 add_hook(&match_condition_set, CONDITION_HOOK);
511 add_hook(&match_assign, ASSIGNMENT_HOOK);
512 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
513 all_return_states_hook(&process_states);
515 select_return_implies_hook(UNITS, &set_implied_units);
516 select_caller_info_hook(&set_param_units, UNITS);
518 add_allocation_hook(&match_allocation);