param_key: fix container of when no struct member is referenced
[smatch.git] / check_select_type.c
blob1c932d02c2331294d4abac2ef132bec5f529e63e
1 /*
2 * Copyright (C) 2021 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 * Type promotion with selects doesn't work how you might expect:
20 * long foo = bar ? u_int_type : -12;
21 * The -12 is promoted to unsigned int and the sign is not expanded.
25 #include "smatch.h"
26 #include "smatch_extra.h"
28 static int my_id;
30 static bool is_select(struct expression *expr)
32 if (expr->type == EXPR_CONDITIONAL)
33 return true;
34 if (expr->type == EXPR_SELECT)
35 return true;
36 return false;
39 static int is_uint(struct expression *expr)
41 struct symbol *type;
43 type = get_type(expr);
44 if (type_positive_bits(type) == 32)
45 return true;
46 return false;
49 static int is_suspicious_int(struct expression *expr)
51 struct symbol *type;
52 struct range_list *rl;
54 type = get_type(expr);
55 if (type_positive_bits(type) != 31)
56 return false;
58 get_absolute_rl(expr, &rl);
59 if (!sval_is_negative(rl_min(rl)))
60 return false;
62 if (expr->type == EXPR_BINOP && expr->op == SPECIAL_LEFTSHIFT)
63 return false;
65 return true;
68 static void match_assign(struct expression *expr)
70 struct expression *right, *one, *two;
71 struct symbol *type;
72 char *name;
74 if (expr->op != '=')
75 return;
77 right = strip_expr(expr->right);
78 if (!is_select(right))
79 return;
81 type = get_type(expr->left);
82 if (type_bits(type) != 64)
83 return;
85 if (right->cond_true)
86 one = right->cond_true;
87 else
88 one = right->conditional;
89 two = right->cond_false;
91 if (is_uint(one) && is_suspicious_int(two)) {
92 name = expr_to_str(two);
93 sm_warning("check sign expansion for '%s'", name);
94 free_string(name);
95 return;
98 if (is_uint(two) && is_suspicious_int(one)) {
99 name = expr_to_str(one);
100 sm_warning("check sign expansion for '%s'", name);
101 free_string(name);
102 return;
106 void check_select_type(int id)
108 my_id = id;
109 add_hook(match_assign, RAW_ASSIGNMENT_HOOK);