1 /*
   2  * Copyright (C) 2014 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 
  20 static int my_id;
  21 
  22 static void match_binop(struct expression *expr)
  23 {
  24         struct symbol *type;
  25         sval_t bits;
  26 
  27         if (expr->op != SPECIAL_RIGHTSHIFT)
  28                 return;
  29 
  30         if (!get_implied_value(expr->right, &bits))
  31                 return;
  32 
  33         type = get_type(expr->left);
  34         if (!type)
  35                 return;
  36         if (type_bits(type) == -1 || type_bits(type) > bits.value)
  37                 return;
  38         if (is_ignored_expr(my_id, expr))
  39                 return;
  40         sm_warning("right shifting more than type allows %d vs %lld", type_bits(type), bits.value);
  41 }
  42 
  43 static void match_binop2(struct expression *expr)
  44 {
  45         struct expression *left;
  46         struct expression *tmp;
  47         sval_t mask, shift;
  48 
  49         if (expr->op != SPECIAL_RIGHTSHIFT)
  50                 return;
  51 
  52         left = strip_expr(expr->left);
  53         tmp = get_assigned_expr(left);
  54         if (tmp)
  55                 left = tmp;
  56         if (left->type != EXPR_BINOP || left->op != '&')
  57                 return;
  58 
  59         if (!get_implied_value(expr->right, &shift))
  60                 return;
  61         if (!get_implied_value(left->right, &mask))
  62                 return;
  63 
  64         if (mask.uvalue >> shift.uvalue)
  65                 return;
  66 
  67         sm_warning("mask and shift to zero");
  68 }
  69 
  70 static void match_assign(struct expression *expr)
  71 {
  72         struct symbol *type;
  73         sval_t bits;
  74 
  75         if (expr->op != SPECIAL_SHR_ASSIGN)
  76                 return;
  77 
  78         if (!get_implied_value(expr->right, &bits))
  79                 return;
  80         type = get_type(expr->left);
  81         if (!type)
  82                 return;
  83         if (type_bits(type) > bits.value)
  84                 return;
  85         sm_warning("right shift assign to zero");
  86 }
  87 
  88 void check_shift_to_zero(int id)
  89 {
  90         my_id = id;
  91 
  92         add_hook(&match_binop, BINOP_HOOK);
  93         add_hook(&match_binop2, BINOP_HOOK);
  94 
  95         add_hook(&match_assign, ASSIGNMENT_HOOK);
  96 
  97 }