sval: add sval_is_negative()/positive()
[smatch.git] / check_or_vs_and.c
blob5481df4f3eb6a08b68194e9c97267e3fc4da3936
1 /*
2 * sparse/check_or_vs_and.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "smatch.h"
11 #include "smatch_function_hashtable.h"
13 static int my_id;
15 DEFINE_STRING_HASHTABLE_STATIC(unconstant_macros);
17 static int does_inc_dec(struct expression *expr)
19 if (expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) {
20 if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
21 return 1;
22 return does_inc_dec(expr->unop);
24 return 0;
27 static int expr_equiv(struct expression *one, struct expression *two)
29 struct symbol *one_sym, *two_sym;
30 char *one_name = NULL;
31 char *two_name = NULL;
32 int ret = 0;
34 if (does_inc_dec(one) || does_inc_dec(two))
35 return 0;
37 one_name = get_variable_from_expr_complex(one, &one_sym);
38 if (!one_name || !one_sym)
39 goto free;
40 two_name = get_variable_from_expr_complex(two, &two_sym);
41 if (!two_name || !two_sym)
42 goto free;
43 if (one_sym != two_sym)
44 goto free;
45 if (strcmp(one_name, two_name) == 0)
46 ret = 1;
47 free:
48 free_string(one_name);
49 free_string(two_name);
50 return ret;
53 static int inconsistent_check(struct expression *left, struct expression *right)
55 sval_t sval;
57 if (get_value(left->left, &sval)) {
58 if (get_value(right->left, &sval))
59 return expr_equiv(left->right, right->right);
60 if (get_value(right->right, &sval))
61 return expr_equiv(left->right, right->left);
62 return 0;
64 if (get_value(left->right, &sval)) {
65 if (get_value(right->left, &sval))
66 return expr_equiv(left->left, right->right);
67 if (get_value(right->right, &sval))
68 return expr_equiv(left->left, right->left);
69 return 0;
72 return 0;
75 static void check_or(struct expression *expr)
77 if (expr->left->type != EXPR_COMPARE ||
78 expr->left->op != SPECIAL_NOTEQUAL)
79 return;
80 if (expr->right->type != EXPR_COMPARE ||
81 expr->right->op != SPECIAL_NOTEQUAL)
82 return;
83 if (!inconsistent_check(expr->left, expr->right))
84 return;
86 sm_msg("warn: was && intended here instead of ||?");
89 static void check_and(struct expression *expr)
91 if (expr->left->type != EXPR_COMPARE ||
92 expr->left->op != SPECIAL_EQUAL)
93 return;
94 if (expr->right->type != EXPR_COMPARE ||
95 expr->right->op != SPECIAL_EQUAL)
96 return;
97 if (!inconsistent_check(expr->left, expr->right))
98 return;
100 sm_msg("warn: was || intended here instead of &&?");
103 static void match_logic(struct expression *expr)
105 if (expr->type != EXPR_LOGICAL)
106 return;
108 if (expr->op == SPECIAL_LOGICAL_OR)
109 check_or(expr);
110 if (expr->op == SPECIAL_LOGICAL_AND)
111 check_and(expr);
114 static int is_unconstant_macro(struct expression *expr)
116 char *macro;
118 macro = get_macro_name(expr->pos);
119 if (!macro)
120 return 0;
121 if (search_unconstant_macros(unconstant_macros, macro))
122 return 1;
123 return 0;
126 static void match_condition(struct expression *expr)
128 sval_t sval;
130 if (expr->type != EXPR_BINOP)
131 return;
132 if (expr->op == '|') {
133 if (get_value(expr->left, &sval) || get_value(expr->right, &sval))
134 sm_msg("warn: suspicious bitop condition");
135 return;
138 if (expr->op != '&')
139 return;
141 if (get_macro_name(expr->pos))
142 return;
143 if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right))
144 return;
146 if ((get_value(expr->left, &sval) && sval.value == 0) ||
147 (get_value(expr->right, &sval) && sval.value == 0))
148 sm_msg("warn: bitwise AND condition is false here");
151 static void match_binop(struct expression *expr)
153 sval_t left, right, sval;
155 if (expr->op != '&')
156 return;
157 if (!get_value(expr, &sval) || sval.value != 0)
158 return;
159 if (get_macro_name(expr->pos))
160 return;
161 if (!get_value(expr->left, &left) || !get_value(expr->right, &right))
162 return;
163 sm_msg("warn: odd binop '0x%llx & 0x%llx'", left.uvalue, right.uvalue);
166 void check_or_vs_and(int id)
168 my_id = id;
170 unconstant_macros = create_function_hashtable(100);
171 load_strings("unconstant_macros", unconstant_macros);
173 add_hook(&match_logic, LOGIC_HOOK);
174 add_hook(&match_condition, CONDITION_HOOK);
175 if (option_spammy)
176 add_hook(&match_binop, BINOP_HOOK);