user_data: improve tracking set vs passed in user data
[smatch.git] / check_or_vs_and.c
blob2e5f8e6807a53abc6be262d0a6e8e8981060d3ba
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 = expr_to_str_sym(one, &one_sym);
38 if (!one_name || !one_sym)
39 goto free;
40 two_name = expr_to_str_sym(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 struct expression *left, *right;
79 left = strip_expr(expr->left);
80 right = strip_expr(expr->right);
82 if (left->type != EXPR_COMPARE ||
83 left->op != SPECIAL_NOTEQUAL)
84 return;
85 if (right->type != EXPR_COMPARE ||
86 right->op != SPECIAL_NOTEQUAL)
87 return;
88 if (!inconsistent_check(left, right))
89 return;
91 sm_msg("warn: was && intended here instead of ||?");
94 static void check_and(struct expression *expr)
96 struct expression *left, *right;
98 left = strip_expr(expr->left);
99 right = strip_expr(expr->right);
101 if (left->type != EXPR_COMPARE ||
102 left->op != SPECIAL_EQUAL)
103 return;
104 if (right->type != EXPR_COMPARE ||
105 right->op != SPECIAL_EQUAL)
106 return;
107 if (!inconsistent_check(left, right))
108 return;
110 sm_msg("warn: was || intended here instead of &&?");
113 static void match_logic(struct expression *expr)
115 if (expr->type != EXPR_LOGICAL)
116 return;
118 if (expr->op == SPECIAL_LOGICAL_OR)
119 check_or(expr);
120 if (expr->op == SPECIAL_LOGICAL_AND)
121 check_and(expr);
124 static int is_unconstant_macro(struct expression *expr)
126 char *macro;
128 macro = get_macro_name(expr->pos);
129 if (!macro)
130 return 0;
131 if (search_unconstant_macros(unconstant_macros, macro))
132 return 1;
133 return 0;
136 static void match_condition(struct expression *expr)
138 sval_t sval;
140 if (expr->type != EXPR_BINOP)
141 return;
142 if (expr->op == '|') {
143 if (get_value(expr->left, &sval) || get_value(expr->right, &sval))
144 sm_msg("warn: suspicious bitop condition");
145 return;
148 if (expr->op != '&')
149 return;
151 if (get_macro_name(expr->pos))
152 return;
153 if (is_unconstant_macro(expr->left) || is_unconstant_macro(expr->right))
154 return;
156 if ((get_value(expr->left, &sval) && sval.value == 0) ||
157 (get_value(expr->right, &sval) && sval.value == 0))
158 sm_msg("warn: bitwise AND condition is false here");
161 static void match_binop(struct expression *expr)
163 sval_t left, right, sval;
165 if (expr->op != '&')
166 return;
167 if (!get_value(expr, &sval) || sval.value != 0)
168 return;
169 if (get_macro_name(expr->pos))
170 return;
171 if (!get_value(expr->left, &left) || !get_value(expr->right, &right))
172 return;
173 sm_msg("warn: odd binop '0x%llx & 0x%llx'", left.uvalue, right.uvalue);
176 void check_or_vs_and(int id)
178 my_id = id;
180 unconstant_macros = create_function_hashtable(100);
181 load_strings("unconstant_macros", unconstant_macros);
183 add_hook(&match_logic, LOGIC_HOOK);
184 add_hook(&match_condition, CONDITION_HOOK);
185 if (option_spammy)
186 add_hook(&match_binop, BINOP_HOOK);