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 
  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 
  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 
  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 
  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 
  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 
  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 
 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 
 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 
 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 
 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 
 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 }