kernel: fix a type bug handling err_cast()
[smatch.git] / check_or_vs_and.c
blob8d63c3d489da281c293f693646b5e976d70b0fbf
1 /*
2 * Copyright (C) 2012 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_function_hashtable.h"
21 static int my_id;
23 DEFINE_STRING_HASHTABLE_STATIC(unconstant_macros);
25 static int does_inc_dec(struct expression *expr)
27 if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) {
28 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
29 return 1;
30 return does_inc_dec(expr->unop);
32 return 0;
35 static int expr_equiv_no_inc_dec(struct expression *one, struct expression *two)
37 if (does_inc_dec(one) || does_inc_dec(two))
38 return 0;
39 return expr_equiv(one, two);
42 static int inconsistent_check(struct expression *left, struct expression *right)
44 sval_t sval;
46 if (get_value(left->left, &sval)) {
47 if (get_value(right->left, &sval))
48 return expr_equiv_no_inc_dec(left->right, right->right);
49 if (get_value(right->right, &sval))
50 return expr_equiv_no_inc_dec(left->right, right->left);
51 return 0;
53 if (get_value(left->right, &sval)) {
54 if (get_value(right->left, &sval))
55 return expr_equiv_no_inc_dec(left->left, right->right);
56 if (get_value(right->right, &sval))
57 return expr_equiv_no_inc_dec(left->left, right->left);
58 return 0;
61 return 0;
64 static void check_or(struct expression *expr)
66 struct expression *left, *right;
68 left = strip_expr(expr->left);
69 right = strip_expr(expr->right);
71 if (left->type != EXPR_COMPARE || left->op != SPECIAL_NOTEQUAL)
72 return;
73 if (right->type != EXPR_COMPARE || right->op != SPECIAL_NOTEQUAL)
74 return;
75 if (!inconsistent_check(left, right))
76 return;
78 sm_warning("was && intended here instead of ||?");
81 static int is_kernel_min_macro(struct expression *expr)
83 char *macro;
85 if (option_project != PROJ_KERNEL)
86 return 0;
87 macro = get_macro_name(expr->pos);
88 if (!macro)
89 return 0;
90 if (strcmp(macro, "min") == 0 ||
91 strcmp(macro, "min_t") == 0 ||
92 strcmp(macro, "max") == 0 ||
93 strcmp(macro, "max_t") == 0)
94 return 1;
95 return 0;
98 static void check_and(struct expression *expr)
100 struct expression *left, *right;
102 if (is_kernel_min_macro(expr))
103 return;
105 left = strip_expr(expr->left);
106 right = strip_expr(expr->right);
108 if (left->type != EXPR_COMPARE || left->op != SPECIAL_EQUAL)
109 return;
110 if (right->type != EXPR_COMPARE || right->op != SPECIAL_EQUAL)
111 return;
112 if (!inconsistent_check(left, right))
113 return;
115 sm_warning("was || intended here instead of &&?");
118 static void match_logic(struct expression *expr)
120 if (expr->type != EXPR_LOGICAL)
121 return;
123 if (expr->op == SPECIAL_LOGICAL_OR)
124 check_or(expr);
125 if (expr->op == SPECIAL_LOGICAL_AND)
126 check_and(expr);
129 static int is_unconstant_macro(struct expression *expr)
131 char *macro;
133 macro = get_macro_name(expr->pos);
134 if (!macro)
135 return 0;
136 if (search_unconstant_macros(unconstant_macros, macro))
137 return 1;
138 return 0;
141 static void match_condition(struct expression *expr)
143 sval_t sval;
145 if (expr->type != EXPR_BINOP)
146 return;
147 if (expr->op == '|') {
148 if (get_value(expr->left, &sval) || get_value(expr->right, &sval))
149 sm_warning("suspicious bitop condition");
150 return;
153 if (expr->op != '&')
154 return;
156 if (get_macro_name(expr->pos))
157 return;
158 if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right))
159 return;
161 if ((get_value(expr->left, &sval) && sval.value == 0) ||
162 (get_value(expr->right, &sval) && sval.value == 0))
163 sm_warning("bitwise AND condition is false here");
166 static void match_binop(struct expression *expr)
168 sval_t left, right, sval;
170 if (expr->op != '&')
171 return;
172 if (!get_value(expr, &sval) || sval.value != 0)
173 return;
174 if (get_macro_name(expr->pos))
175 return;
176 if (!get_value(expr->left, &left) || !get_value(expr->right, &right))
177 return;
178 sm_warning("odd binop '0x%llx & 0x%llx'", left.uvalue, right.uvalue);
181 void check_or_vs_and(int id)
183 my_id = id;
185 unconstant_macros = create_function_hashtable(100);
186 load_strings("unconstant_macros", unconstant_macros);
188 add_hook(&match_logic, LOGIC_HOOK);
189 add_hook(&match_condition, CONDITION_HOOK);
190 if (option_spammy)
191 add_hook(&match_binop, BINOP_HOOK);