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
19 #include "smatch_slist.h"
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
);
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
)
50 if (strcmp(str
, "unit_bit") == 0)
52 if (strcmp(str
, "unit_byte") == 0)
54 if (strcmp(str
, "unit_page") == 0)
56 if (strcmp(str
, "unit_msec") == 0)
58 if (strcmp(str
, "unit_jiffy") == 0)
60 if (strcmp(str
, "unit_long") == 0)
62 if (strcmp(str
, "unit_array_size") == 0)
63 return &unit_array_size
;
64 if (strcmp(str
, "unknown") == 0)
70 static struct smatch_state
*get_units_from_type(struct expression
*expr
);
72 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
74 if (cur
->state
== other
->state
)
77 if (cur
->state
== &undefined
|| cur
->state
== &merged
||
78 other
->state
== &undefined
|| other
->state
== &merged
)
81 if (!__cur_stmt
|| __cur_stmt
->type
!= STMT_RETURN
)
82 sm_msg("warn: ambiguous units merge '%s' '%s' or '%s'",
83 cur
->name
, cur
->state
->name
, other
->state
->name
);
86 static struct smatch_state
*merge_units(struct smatch_state
*s1
, struct smatch_state
*s2
)
95 static bool is_ignored_type(char *name
)
99 if (strcmp(name
, "(union anonymous)->__val") == 0)
101 if (strncmp(name
, "(struct fs_parse_result)", 24) == 0)
106 static void store_type_in_db(struct expression
*expr
, struct smatch_state
*state
)
108 struct smatch_state
*old_units
;
111 member
= get_member_name(expr
);
114 if (is_ignored_type(member
))
117 old_units
= get_units_from_type(expr
);
118 if (old_units
&& old_units
!= state
) {
119 sm_msg("warn: other places set '%s' to '%s' instead of '%s'",
120 member
, old_units
->name
, state
->name
);
122 // sm_msg("%s: insert: member='%s' units='%s'", __func__, member, state->name);
123 sql_insert_cache(type_info
, "0x%llx, %d, '%s', '%s'", get_base_file_id(), UNITS
, member
, state
->name
);
126 static void set_units(struct expression
*expr
, struct smatch_state
*state
)
131 set_state_expr(my_id
, expr
, state
);
132 store_type_in_db(expr
, state
);
135 static bool is_PAGE_SHIFT(struct expression
*expr
)
139 macro
= get_macro_name(expr
->pos
);
140 if (macro
&& strcmp(macro
, "PAGE_SHIFT") == 0)
145 static bool is_PAGE_SIZE(struct expression
*expr
)
149 macro
= get_macro_name(expr
->pos
);
150 if (macro
&& strcmp(macro
, "PAGE_SIZE") == 0)
155 static bool is_BITS_PER_LONG(struct expression
*expr
)
159 macro
= get_macro_name(expr
->pos
);
160 if (macro
&& strcmp(macro
, "BITS_PER_LONG") == 0)
165 static struct smatch_state
*binop_helper(struct expression
*left
, int op
, struct expression
*right
)
167 struct smatch_state
*left_state
, *right_state
;
172 // subtracting pointers gives unit_byte
175 left_state
= get_units(left
);
176 right_state
= get_units(right
);
177 if (left_state
== &unit_array_size
||
178 right_state
== &unit_array_size
)
181 return left_state
? left_state
: right_state
;
183 /* FIXME: A multiply is almost always bytes but it can be bits. */
184 if (is_PAGE_SIZE(right
))
186 if (!get_implied_value(right
, &val
))
188 /* 4096 is almost always a unit_page -> bytes converstion */
189 if (val
.value
== 4096)
193 if (is_BITS_PER_LONG(right
))
195 if (is_PAGE_SIZE(right
))
197 if (!get_implied_value(right
, &val
))
199 if (val
.value
== 4096)
202 case SPECIAL_LEFTSHIFT
:
203 if (is_PAGE_SHIFT(right
))
206 case SPECIAL_RIGHTSHIFT
:
207 if (is_PAGE_SHIFT(right
))
214 static struct smatch_state
*get_units_binop(struct expression
*expr
)
216 return binop_helper(expr
->left
, expr
->op
, expr
->right
);
219 static struct smatch_state
*get_units_call(struct expression
*expr
)
221 expr
= strip_expr(expr
);
222 if (!expr
|| expr
->type
!= EXPR_CALL
)
225 if (sym_name_is("unit_msecs_to_jiffies", expr
->fn
))
227 if (sym_name_is("jiffies_to_unit_msecs", expr
->fn
))
233 static int db_units(void *_units
, int argc
, char **argv
, char **azColName
)
235 char **units
= _units
;
238 if (strcmp(*units
, argv
[0]) == 0)
241 *units
= alloc_string("unknown");
245 *units
= alloc_string(argv
[0]);
249 static struct smatch_state
*get_units_from_type(struct expression
*expr
)
253 struct smatch_state
*ret
= NULL
;
255 member
= get_member_name(expr
);
258 if (strcmp(member
, "(struct vm_area_struct)->vm_pgoff") == 0)
260 cache_sql(&db_units
, &units
, "select value from type_info where type = %d and key = '%s';",
262 run_sql(&db_units
, &units
, "select value from type_info where type = %d and key = '%s';",
268 ret
= str_to_units(units
);
275 struct smatch_state
*get_units(struct expression
*expr
)
277 struct smatch_state
*state
;
280 expr
= strip_expr(expr
);
284 if (expr
->type
== EXPR_PTRSIZEOF
||
285 expr
->type
== EXPR_SIZEOF
)
288 ident
= pos_ident(expr
->pos
);
290 if (strcmp(ident
, "sizeof") == 0 ||
291 strcmp(ident
, "PAGE_SIZE") == 0)
293 if (strcmp(ident
, "jiffies") == 0)
295 if (strcmp(ident
, "BITS_PER_LONG") == 0)
297 if (strcmp(ident
, "BITS_PER_LONG_LONG") == 0)
299 if (strcmp(ident
, "ARRAY_SIZE") == 0)
300 return &unit_array_size
;
303 if (expr
->type
== EXPR_BINOP
)
304 return get_units_binop(expr
);
306 if (expr
->type
== EXPR_CALL
)
307 return get_units_call(expr
);
309 state
= get_state_expr(my_id
, expr
);
310 if (state
== &merged
|| state
== &undefined
)
315 return get_units_from_type(expr
);
318 bool is_array_size_units(struct expression
*expr
)
320 return get_units(expr
) == &unit_array_size
;
323 static void match_allocation(struct expression
*expr
,
324 const char *name
, struct symbol
*sym
,
325 struct allocation_info
*info
)
327 struct expression
*right
, *left
;
329 if (info
->nr_elems
&& info
->elem_size
) {
330 left
= info
->nr_elems
;
331 right
= info
->elem_size
;
332 } else if (info
->total_size
&&
333 info
->total_size
->type
== EXPR_BINOP
&&
334 info
->total_size
->op
== '*') {
335 left
= strip_expr(info
->total_size
->left
);
336 right
= strip_expr(info
->total_size
->right
);
341 if (get_units(left
) == &unit_byte
)
342 set_units(right
, &unit_array_size
);
343 if (get_units(right
) == &unit_byte
)
344 set_units(left
, &unit_array_size
);
347 static void check_mult(struct expression
*expr
)
349 struct smatch_state
*left
, *right
;
350 int bit_found
= 0, byte_found
= 0;
353 left
= get_units(expr
->left
);
354 right
= get_units(expr
->right
);
356 if (left
== &unit_bit
|| right
== &unit_bit
)
358 if (left
== &unit_byte
|| right
== &unit_byte
)
361 if (bit_found
&& byte_found
) {
362 name
= expr_to_str(expr
);
363 sm_warning("multiplying bits * bytes '%s'", name
);
368 static void check_add_sub(struct expression
*expr
)
370 struct smatch_state
*left
, *right
;
374 type
= get_type(expr
->left
);
375 if (type
&& (type
->type
== SYM_PTR
|| type
->type
== SYM_ARRAY
))
378 left
= get_units(expr
->left
);
379 right
= get_units(expr
->right
);
381 if (!left
|| !right
|| left
== right
)
383 str
= expr_to_str(expr
);
384 sm_warning("missing conversion: '%s' '%s %s %s'", str
, left
->name
, show_special(expr
->op
), right
->name
);
389 static void match_binop_check(struct expression
*expr
)
402 static void match_binop_set(struct expression
*expr
)
404 struct smatch_state
*left
, *right
;
407 if (expr
->op
== SPECIAL_LEFTSHIFT
&& is_PAGE_SHIFT(expr
->right
)) {
408 set_units(expr
->left
, &unit_page
);
412 if (expr
->op
== SPECIAL_RIGHTSHIFT
&& is_PAGE_SHIFT(expr
->right
)) {
413 set_units(expr
->left
, &unit_byte
);
417 if (expr
->op
!= '+' && expr
->op
!= '-')
420 type
= get_type(expr
->left
);
421 if (type
&& (type
->type
== SYM_PTR
|| type
->type
== SYM_ARRAY
))
424 left
= get_units(expr
->left
);
425 right
= get_units(expr
->right
);
428 set_units(expr
->right
, left
);
430 set_units(expr
->left
, right
);
433 static void match_condition_check(struct expression
*expr
)
435 struct smatch_state
*left
, *right
;
438 if (expr
->type
!= EXPR_COMPARE
)
441 left
= get_units(expr
->left
);
442 right
= get_units(expr
->right
);
449 str
= expr_to_str(expr
);
450 sm_msg("warn: comparing different units: '%s' '%s %s %s'", str
, left
->name
, show_special(expr
->op
), right
->name
);
454 static void match_condition_set(struct expression
*expr
)
456 struct smatch_state
*left
, *right
;
458 if (expr
->type
!= EXPR_COMPARE
)
461 left
= get_units(expr
->left
);
462 right
= get_units(expr
->right
);
465 set_units(expr
->right
, left
);
467 set_units(expr
->left
, right
);
470 static void match_assign(struct expression
*expr
)
472 struct smatch_state
*state
= NULL
;
474 if (__in_fake_assign
)
479 state
= get_units(expr
->right
);
481 case SPECIAL_SHR_ASSIGN
:
482 case SPECIAL_SHL_ASSIGN
:
483 case SPECIAL_DIV_ASSIGN
:
484 case SPECIAL_MUL_ASSIGN
:
485 state
= binop_helper(expr
->left
, op_remove_assign(expr
->op
),
490 set_units(expr
->left
, state
);
492 // clear_units(expr->left);
495 static void set_implied_units(struct expression
*call
, struct expression
*arg
, char *key
, char *value
)
497 struct smatch_state
*state
;
501 state
= str_to_units(value
);
504 name
= get_variable_from_key(arg
, key
, &sym
);
507 set_state(my_id
, name
, sym
, state
);
512 static void set_param_units(const char *name
, struct symbol
*sym
, char *key
, char *value
)
514 struct smatch_state
*state
;
516 state
= str_to_units(value
);
519 set_state(my_id
, sym
->ident
->name
, sym
, state
);
522 static void set_param_units_from_table(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
524 const char *value
= data
;
525 struct smatch_state
*state
;
527 state
= str_to_units(value
);
530 set_state(my_id
, name
, sym
, state
);
533 static void match_call_info(struct expression
*expr
)
535 struct expression
*arg
;
536 struct smatch_state
*state
;
540 if (expr
->fn
->type
!= EXPR_SYMBOL
)
542 fn_name
= expr_to_var(expr
->fn
);
546 FOR_EACH_PTR(expr
->args
, arg
) {
548 state
= get_units(arg
);
551 // sql_insert_cache(return_implies, "0x%llx, '%s', 0, %d, %d, %d, '%s', '%s'",
552 // get_base_file_id(), fn_name, is_static(expr->fn), UNITS, param, "$", state->name);
553 sql_insert_caller_info(expr
, UNITS
, param
, "$", state
->name
);
555 } END_FOR_EACH_PTR(arg
);
557 free_string(fn_name
);
560 static void process_states(void)
563 struct smatch_state
*state
, *start_state
;
566 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, arg
) {
568 state
= get_state(my_id
, arg
->ident
->name
, arg
);
569 if (!state
|| state
== &merged
|| state
== &undefined
)
571 start_state
= get_state_stree(get_start_states(), my_id
, arg
->ident
->name
, arg
);
572 if (state
== start_state
)
574 sql_insert_cache(return_implies
, "0x%llx, '%s', 0, %d, %d, %d, '%s', '%s'",
575 get_base_file_id(), get_function(), fn_static(), UNITS
, param
, "$", state
->name
);
576 } END_FOR_EACH_PTR(arg
);
579 char *get_unit_str(struct expression
*expr
)
581 struct smatch_state
*state
;
583 state
= get_units(expr
);
586 return (char *)state
->name
;
589 void register_units(int id
)
591 struct type_info
*info
;
596 for (i
= 0; i
< ARRAY_SIZE(func_table
); i
++) {
597 info
= &func_table
[i
];
598 add_function_param_key_hook(info
->name
,
599 set_param_units_from_table
,
600 info
->param
, info
->key
,
601 (void *)info
->value
);
604 add_pre_merge_hook(my_id
, &pre_merge_hook
);
605 add_merge_hook(my_id
, &merge_units
);
607 add_hook(&match_binop_check
, BINOP_HOOK
);
608 add_hook(&match_binop_set
, BINOP_HOOK
);
609 add_hook(&match_condition_check
, CONDITION_HOOK
);
610 add_hook(&match_condition_set
, CONDITION_HOOK
);
611 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
612 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
613 all_return_states_hook(&process_states
);
615 select_return_implies_hook(UNITS
, &set_implied_units
);
616 select_caller_info_hook(&set_param_units
, UNITS
);
618 add_allocation_hook(&match_allocation
);