1 /*
   2  * Copyright (C) 2015 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_slist.h"
  20 #include "smatch_extra.h"
  21 
  22 static int my_id;
  23 static int link_id;
  24 
  25 static struct smatch_state *safe_state(struct expression *expr)
  26 {
  27         struct smatch_state *state;
  28 
  29         state = __alloc_smatch_state(0);
  30         expr = strip_expr(expr);
  31         state->name = alloc_sname("safe");
  32         state->data = expr;
  33         return state;
  34 }
  35 
  36 static char *save_links(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
  37 {
  38         struct var_sym *vs;
  39         char *name;
  40 
  41         name = expr_to_chunk_sym_vsl(expr, sym, vsl);
  42         if (!name || !*vsl) {
  43                 free_string(name);
  44                 return NULL;
  45         }
  46 
  47         FOR_EACH_PTR(*vsl, vs) {
  48                 store_link(link_id, vs->var, vs->sym, name, *sym);
  49         } END_FOR_EACH_PTR(vs);
  50 
  51         return name;
  52 }
  53 
  54 static void match_divide(struct expression *expr)
  55 {
  56         struct expression *left, *right, *binop;
  57         struct symbol *type;
  58         char *name;
  59         struct symbol *sym;
  60         struct var_sym_list *vsl;
  61         sval_t max;
  62 
  63         if (expr->type != EXPR_COMPARE)
  64                 return;
  65         if (expr->op != '>' && expr->op != SPECIAL_UNSIGNED_GT &&
  66             expr->op != SPECIAL_GTE && expr->op != SPECIAL_UNSIGNED_GTE)
  67                 return;
  68 
  69         left = strip_parens(expr->left);
  70         right = strip_parens(expr->right);
  71 
  72         if (right->type != EXPR_BINOP || right->op != '/')
  73                 return;
  74         if (!get_value(right->left, &max))
  75                 return;
  76         if (max.value != INT_MAX && max.value != UINT_MAX &&
  77             max.value != LLONG_MAX && max.uvalue != ULLONG_MAX)
  78                 return;
  79 
  80         type = get_type(expr);
  81         if (!type)
  82                 return;
  83         if (type_bits(type) != 32 && type_bits(type) != 64)
  84                 return;
  85 
  86 
  87         binop = binop_expression(left, '*', right->right);
  88 
  89         name = save_links(binop, &sym, &vsl);
  90         if (!name)
  91                 return;
  92         set_true_false_states(my_id, name, sym, NULL, safe_state(binop));
  93         free_string(name);
  94 }
  95 
  96 static void match_overflow_to_less_than(struct expression *expr)
  97 {
  98         struct expression *left, *right;
  99         struct symbol *type;
 100         char *name;
 101         struct symbol *sym;
 102         struct var_sym_list *vsl;
 103 
 104         if (expr->type != EXPR_COMPARE)
 105                 return;
 106         if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
 107                 return;
 108 
 109         left = strip_parens(expr->left);
 110         right = strip_parens(expr->right);
 111 
 112         if (left->op != '+')
 113                 return;
 114 
 115         type = get_type(expr);
 116         if (!type)
 117                 return;
 118         if (type_bits(type) != 32 && type_bits(type) != 64)
 119                 return;
 120 
 121         if (!expr_equiv(left->left, right) && !expr_equiv(left->right, right))
 122                 return;
 123 
 124         name = save_links(left, &sym, &vsl);
 125         if (!name)
 126                 return;
 127         set_true_false_states(my_id, name, sym, NULL, safe_state(left));
 128         free_string(name);
 129 }
 130 
 131 static void match_condition(struct expression *expr)
 132 {
 133         match_overflow_to_less_than(expr);
 134         match_divide(expr);
 135 }
 136 
 137 int can_integer_overflow(struct symbol *type, struct expression *expr)
 138 {
 139         int op;
 140         sval_t lmax, rmax, res;
 141 
 142         if (!type)
 143                 type = &int_ctype;
 144 
 145         expr = strip_expr(expr);
 146 
 147         if (expr->type == EXPR_ASSIGNMENT) {
 148                 switch(expr->op) {
 149                 case SPECIAL_MUL_ASSIGN:
 150                         op = '*';
 151                         break;
 152                 case SPECIAL_ADD_ASSIGN:
 153                         op = '+';
 154                         break;
 155                 case SPECIAL_SHL_ASSIGN:
 156                         op = SPECIAL_LEFTSHIFT;
 157                         break;
 158                 default:
 159                         return 0;
 160                 }
 161         } else if (expr->type == EXPR_BINOP) {
 162                 if (expr->op != '*' && expr->op != '+' && expr->op != SPECIAL_LEFTSHIFT)
 163                         return 0;
 164                 op = expr->op;
 165         } else {
 166                 return 0;
 167         }
 168 
 169         get_absolute_max(expr->left, &lmax);
 170         get_absolute_max(expr->right, &rmax);
 171 
 172         if (sval_binop_overflows(lmax, op, rmax))
 173                 return 1;
 174 
 175         res = sval_binop(lmax, op, rmax);
 176         if (sval_cmp(res, sval_type_max(type)) > 0)
 177                 return 1;
 178         return 0;
 179 }
 180 
 181 int can_integer_overflow_expr(struct expression *expr)
 182 {
 183         struct symbol *type;
 184         struct smatch_state *state;
 185         char *name;
 186         struct symbol *sym;
 187         int ret;
 188 
 189         type = get_type(expr);
 190         if (!type)
 191                 return 0;
 192 
 193         if (!can_integer_overflow(type, expr))
 194                 return 0;
 195 
 196         name = expr_to_known_chunk_sym(expr, &sym);
 197         if (!name || !sym)
 198                 goto free;
 199 
 200         state = get_state(my_id, name, sym);
 201         if (state && state->data)
 202                 ret = 0;
 203 free:
 204         free_string(name);
 205         return ret;
 206 }
 207 
 208 static int get_arg_nr(struct expression *call, struct expression *expr)
 209 {
 210         struct expression *arg;
 211         int i;
 212 
 213         i = -1;
 214         FOR_EACH_PTR(call->args, arg) {
 215                 i++;
 216                 if (expr_equiv(arg, expr))
 217                         return i;
 218         } END_FOR_EACH_PTR(arg);
 219 
 220         return -1;
 221 }
 222 
 223 static void check_links(struct expression *call, struct expression *arg, int nr, struct sm_state *sm, void *_vsl)
 224 {
 225         struct var_sym_list *vsl = _vsl;
 226         struct var_sym *vs;
 227         struct smatch_state *state;
 228         struct expression *expr;
 229         int left = -1;
 230         int right = -1;
 231 
 232         FOR_EACH_PTR(vsl, vs) {
 233                 state = get_state(my_id, vs->var, vs->sym);
 234                 if (!state || !state->data)
 235                         continue;
 236 
 237                 expr = state->data;
 238 
 239                 if (expr_equiv(arg, expr->left)) {
 240                         left = nr;
 241                         right = get_arg_nr(call, expr->right);
 242                 } else if (expr_equiv(arg, expr->right)) {
 243                         left = get_arg_nr(call, expr->left);
 244                         right = nr;
 245                 }
 246 
 247                 if (left == -1 || right == -1)
 248                         continue;
 249 
 250                 left = -1;
 251                 right = -1;
 252         } END_FOR_EACH_PTR(vs);
 253 }
 254 
 255 static void match_call_info(struct expression *call)
 256 {
 257         struct expression *arg;
 258         struct sm_state *link;
 259         struct stree *done = NULL;
 260         int i;
 261 
 262         i = -1;
 263         FOR_EACH_PTR(call->args, arg) {
 264                 i++;
 265 
 266                 link = get_sm_state_expr(link_id, arg);
 267                 if (!link)
 268                         continue;
 269 
 270                 if (get_state_stree(done, my_id, link->state->name, NULL))
 271                         continue;
 272 //              set_state_stree(&done, my_id, link->state->name, NULL, &undefined);
 273 
 274                 check_links(call, arg, i, link, link->state->data);
 275         } END_FOR_EACH_PTR(arg);
 276 
 277         free_stree(&done);
 278 }
 279 
 280 void register_integer_overflow(int id)
 281 {
 282         my_id = id;
 283         set_dynamic_states(my_id);
 284         add_hook(&match_condition, CONDITION_HOOK);
 285         add_hook(&match_call_info, FUNCTION_CALL_HOOK);
 286 }
 287 
 288 void register_integer_overflow_links(int id)
 289 {
 290         link_id = id;
 291         set_up_link_functions(my_id, link_id);
 292 }