1 /*
2  * Copyright (C) 2012 Oracle.
3  *
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.
8  *
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.
13  *
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
16  */
17 
18 #include "smatch.h"
19 #include "smatch_function_hashtable.h"
20 
21 static int my_id;
22 
23 DEFINE_STRING_HASHTABLE_STATIC(unconstant_macros);
24 
does_inc_dec(struct expression * expr)25 static int does_inc_dec(struct expression *expr)
26 {
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);
31 	}
32 	return 0;
33 }
34 
expr_equiv_no_inc_dec(struct expression * one,struct expression * two)35 static int expr_equiv_no_inc_dec(struct expression *one, struct expression *two)
36 {
37 	if (does_inc_dec(one) || does_inc_dec(two))
38 		return 0;
39 	return expr_equiv(one, two);
40 }
41 
inconsistent_check(struct expression * left,struct expression * right)42 static int inconsistent_check(struct expression *left, struct expression *right)
43 {
44 	sval_t sval;
45 
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;
52 	}
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;
59 	}
60 
61 	return 0;
62 }
63 
check_or(struct expression * expr)64 static void check_or(struct expression *expr)
65 {
66 	struct expression *left, *right;
67 
68 	left = strip_expr(expr->left);
69 	right = strip_expr(expr->right);
70 
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;
77 
78 	sm_warning("was && intended here instead of ||?");
79 }
80 
is_kernel_min_macro(struct expression * expr)81 static int is_kernel_min_macro(struct expression *expr)
82 {
83 	char *macro;
84 
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;
96 }
97 
check_and(struct expression * expr)98 static void check_and(struct expression *expr)
99 {
100 	struct expression *left, *right;
101 
102 	if (is_kernel_min_macro(expr))
103 		return;
104 
105 	left = strip_expr(expr->left);
106 	right = strip_expr(expr->right);
107 
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;
114 
115 	sm_warning("was || intended here instead of &&?");
116 }
117 
match_logic(struct expression * expr)118 static void match_logic(struct expression *expr)
119 {
120 	if (expr->type != EXPR_LOGICAL)
121 		return;
122 
123 	if (expr->op == SPECIAL_LOGICAL_OR)
124 		check_or(expr);
125 	if (expr->op == SPECIAL_LOGICAL_AND)
126 		check_and(expr);
127 }
128 
is_unconstant_macro(struct expression * expr)129 static int is_unconstant_macro(struct expression *expr)
130 {
131 	char *macro;
132 
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;
139 }
140 
match_condition(struct expression * expr)141 static void match_condition(struct expression *expr)
142 {
143 	sval_t sval;
144 
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;
151 	}
152 
153 	if (expr->op != '&')
154 		return;
155 
156 	if (get_macro_name(expr->pos))
157 		return;
158 	if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right))
159 		return;
160 
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");
164 }
165 
match_binop(struct expression * expr)166 static void match_binop(struct expression *expr)
167 {
168 	sval_t left, right, sval;
169 
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);
179 }
180 
check_or_vs_and(int id)181 void check_or_vs_and(int id)
182 {
183 	my_id = id;
184 
185 	unconstant_macros = create_function_hashtable(100);
186 	load_strings("unconstant_macros", unconstant_macros);
187 
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);
192 }
193