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 #include "smatch_extra.h"
  20 
  21 static int my_id;
  22 static int my_return_id;
  23 
  24 STATE(impossible);
  25 
  26 int is_impossible_path(void)
  27 {
  28         if (get_state(my_id, "impossible", NULL) == &impossible)
  29                 return 1;
  30         return 0;
  31 }
  32 
  33 static void handle_compare(struct expression *left, int op, struct expression *right)
  34 {
  35         int true_impossible = 0;
  36         int false_impossible = 0;
  37 
  38         left = strip_expr(left);
  39         while (left && left->type == EXPR_ASSIGNMENT)
  40                 left = strip_expr(left->left);
  41 
  42         if (!possibly_true(left, op, right))
  43                 true_impossible = 1;
  44         if (!possibly_false(left, op, right))
  45                 false_impossible = 1;
  46 
  47         if (!true_impossible && !false_impossible)
  48                 return;
  49 
  50         set_true_false_states(my_id, "impossible", NULL,
  51                               true_impossible ? &impossible : NULL,
  52                               false_impossible ? &impossible : NULL);
  53 
  54         if (inside_loop())
  55                 return;
  56 
  57         set_true_false_states(my_return_id, "impossible", NULL,
  58                               true_impossible ? &impossible : NULL,
  59                               false_impossible ? &impossible : NULL);
  60 }
  61 
  62 static void match_condition(struct expression *expr)
  63 {
  64         if (expr->type == EXPR_COMPARE)
  65                 handle_compare(expr->left, expr->op, expr->right);
  66         else
  67                 handle_compare(expr, SPECIAL_NOTEQUAL, zero_expr());
  68 }
  69 
  70 void set_path_impossible(void)
  71 {
  72         set_state(my_id, "impossible", NULL, &impossible);
  73 
  74         if (inside_loop())
  75                 return;
  76 
  77         set_state(my_return_id, "impossible", NULL, &impossible);
  78 }
  79 
  80 static void match_case(struct expression *expr, struct range_list *rl)
  81 {
  82         if (rl)
  83                 return;
  84         set_path_impossible();
  85 }
  86 
  87 static void print_impossible_return(int return_id, char *return_ranges, struct expression *expr)
  88 {
  89         if (get_state(my_return_id, "impossible", NULL) == &impossible) {
  90                 if (option_debug)
  91                         sm_msg("impossible return.  return_id = %d return ranges = %s", return_id, return_ranges);
  92                 sql_insert_return_states(return_id, return_ranges, CULL_PATH, -1, "", "");
  93         }
  94 }
  95 
  96 void register_impossible(int id)
  97 {
  98         my_id = id;
  99 
 100         add_hook(&match_condition, CONDITION_HOOK);
 101         add_hook(&match_case, CASE_HOOK);
 102 }
 103 
 104 void register_impossible_return(int id)
 105 {
 106         my_return_id = id;
 107 
 108         add_split_return_callback(&print_impossible_return);
 109 }