Print this page
12724 update smatch to 0.6.1-rc1-il-5

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/check_atomic_inc_dec.c
          +++ new/usr/src/tools/smatch/src/check_atomic_inc_dec.c
↓ open down ↓ 7 lines elided ↑ open up ↑
   8    8   *
   9    9   * This program is distributed in the hope that it will be useful,
  10   10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11   11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12   12   * GNU General Public License for more details.
  13   13   *
  14   14   * You should have received a copy of the GNU General Public License
  15   15   * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
  16   16   */
  17   17  
       18 +#include <ctype.h>
       19 +
  18   20  #include "smatch.h"
  19   21  #include "smatch_extra.h"
  20   22  #include "smatch_slist.h"
  21   23  
  22   24  static int my_id;
  23   25  
  24   26  STATE(inc);
  25   27  STATE(orig);
  26   28  STATE(dec);
  27   29  
       30 +static struct smatch_state *unmatched_state(struct sm_state *sm)
       31 +{
       32 +        if (parent_is_gone_var_sym(sm->name, sm->sym))
       33 +                return sm->state;
       34 +        return &undefined;
       35 +}
       36 +
       37 +static struct stree *start_states;
       38 +static struct stree_stack *saved_stack;
       39 +static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
       40 +{
       41 +        struct smatch_state *orig;
       42 +
       43 +        orig = get_state_stree(start_states, my_id, name, sym);
       44 +        if (!orig)
       45 +                set_state_stree(&start_states, my_id, name, sym, start);
       46 +        else if (orig != start)
       47 +                set_state_stree(&start_states, my_id, name, sym, &undefined);
       48 +}
       49 +
       50 +static struct sm_state *get_best_match(const char *key)
       51 +{
       52 +        struct sm_state *sm;
       53 +        struct sm_state *match;
       54 +        int cnt = 0;
       55 +        int start_pos, state_len, key_len, chunks, i;
       56 +
       57 +        if (strncmp(key, "$->", 3) == 0)
       58 +                key += 3;
       59 +
       60 +        key_len = strlen(key);
       61 +        chunks = 0;
       62 +        for (i = key_len - 1; i > 0; i--) {
       63 +                if (key[i] == '>' || key[i] == '.')
       64 +                        chunks++;
       65 +                if (chunks == 2) {
       66 +                        key += (i + 1);
       67 +                        key_len = strlen(key);
       68 +                        break;
       69 +                }
       70 +        }
       71 +
       72 +        FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
       73 +                state_len = strlen(sm->name);
       74 +                if (state_len < key_len)
       75 +                        continue;
       76 +                start_pos = state_len - key_len;
       77 +                if ((start_pos == 0 || !isalnum(sm->name[start_pos - 1])) &&
       78 +                    strcmp(sm->name + start_pos, key) == 0) {
       79 +                        cnt++;
       80 +                        match = sm;
       81 +                }
       82 +        } END_FOR_EACH_SM(sm);
       83 +
       84 +        if (cnt == 1)
       85 +                return match;
       86 +        return NULL;
       87 +}
       88 +
  28   89  static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
  29   90  {
  30      -        struct smatch_state *start_state;
       91 +        struct sm_state *start_sm;
  31   92          struct expression *arg;
  32   93          char *name;
  33   94          struct symbol *sym;
       95 +        bool free_at_end = true;
  34   96  
  35   97          while (expr->type == EXPR_ASSIGNMENT)
  36   98                  expr = strip_expr(expr->right);
  37   99          if (expr->type != EXPR_CALL)
  38  100                  return;
  39  101  
  40  102          arg = get_argument_from_call_expr(expr->args, param);
  41  103          if (!arg)
  42  104                  return;
  43  105  
  44  106          name = get_variable_from_key(arg, key, &sym);
  45  107          if (!name || !sym)
  46  108                  goto free;
  47  109  
  48      -        start_state = get_state(my_id, name, sym);
      110 +        start_sm = get_sm_state(my_id, name, sym);
      111 +        if (!start_sm && inc_dec == ATOMIC_DEC) {
      112 +                start_sm = get_best_match(key);
      113 +                if (start_sm) {
      114 +                        free_string(name);
      115 +                        free_at_end = false;
      116 +                        name = (char *)start_sm->name;
      117 +                        sym = start_sm->sym;
      118 +                }
      119 +        }
  49  120  
  50  121          if (inc_dec == ATOMIC_INC) {
  51      -//              if (start_state == &inc)
  52      -//                      sm_error("XXX double increment '%s'", name);
      122 +                if (!start_sm)
      123 +                        set_start_state(name, sym, &dec);
      124 +//              set_refcount_inc(name, sym);
  53  125                  set_state(my_id, name, sym, &inc);
  54  126          } else {
  55      -//              if (start_state == &dec)
  56      -//                      sm_error("XXX double decrement '%s'", name);
  57      -                if (start_state == &inc)
      127 +//              set_refcount_dec(name, sym);
      128 +                if (!start_sm)
      129 +                        set_start_state(name, sym, &inc);
      130 +
      131 +                if (start_sm && start_sm->state == &inc)
  58  132                          set_state(my_id, name, sym, &orig);
  59  133                  else
  60  134                          set_state(my_id, name, sym, &dec);
  61  135          }
  62  136  
  63  137  free:
  64      -        free_string(name);
      138 +        if (free_at_end)
      139 +                free_string(name);
  65  140  }
  66  141  
  67  142  static void db_inc(struct expression *expr, int param, char *key, char *value)
  68  143  {
  69  144          db_inc_dec(expr, param, key, value, ATOMIC_INC);
  70  145  }
  71  146  
  72  147  static void db_dec(struct expression *expr, int param, char *key, char *value)
  73  148  {
  74  149          db_inc_dec(expr, param, key, value, ATOMIC_DEC);
↓ open down ↓ 41 lines elided ↑ open up ↑
 116  191  static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
 117  192  {
 118  193          struct sm_state *sm;
 119  194          const char *param_name;
 120  195          int param;
 121  196  
 122  197          FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
 123  198                  if (sm->state != &inc &&
 124  199                      sm->state != &dec)
 125  200                          continue;
      201 +                if (parent_is_gone_var_sym(sm->name, sm->sym))
      202 +                        continue;
 126  203                  param = get_param_num_from_sym(sm->sym);
 127  204                  if (param < 0)
 128  205                          continue;
 129  206                  param_name = get_param_name(sm);
 130  207                  if (!param_name)
 131  208                          continue;
 132  209                  sql_insert_return_states(return_id, return_ranges,
 133  210                                           (sm->state == &inc) ? ATOMIC_INC : ATOMIC_DEC,
 134  211                                           param, param_name, "");
 135  212          } END_FOR_EACH_SM(sm);
 136  213  }
 137  214  
 138  215  enum {
 139      -        NEGATIVE, ZERO, POSITIVE,
      216 +        EMPTY, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS
 140  217  };
 141  218  
 142  219  static int success_fail_positive(struct range_list *rl)
 143  220  {
 144  221          if (!rl)
 145      -                return ZERO;
      222 +                return EMPTY;
 146  223  
 147  224          if (sval_is_negative(rl_min(rl)))
 148  225                  return NEGATIVE;
 149  226  
 150  227          if (rl_min(rl).value == 0)
 151  228                  return ZERO;
 152  229  
 153  230          return POSITIVE;
 154  231  }
 155  232  
 156  233  static void check_counter(const char *name, struct symbol *sym)
 157  234  {
 158  235          struct range_list *inc_lines = NULL;
 159  236          struct range_list *dec_lines = NULL;
 160      -        int inc_buckets[3] = {};
 161      -        struct stree *stree;
      237 +        int inc_buckets[NUM_BUCKETS] = {};
      238 +        int dec_buckets[NUM_BUCKETS] = {};
      239 +        struct stree *stree, *orig_stree;
 162  240          struct sm_state *return_sm;
 163  241          struct sm_state *sm;
 164  242          sval_t line = sval_type_val(&int_ctype, 0);
      243 +        int bucket;
 165  244  
 166  245          FOR_EACH_PTR(get_all_return_strees(), stree) {
 167      -                return_sm = get_sm_state_stree(stree, RETURN_ID, "return_ranges", NULL);
      246 +                orig_stree = __swap_cur_stree(stree);
      247 +
      248 +                return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
 168  249                  if (!return_sm)
 169      -                        continue;
      250 +                        goto swap_stree;
 170  251                  line.value = return_sm->line;
 171  252  
 172      -                sm = get_sm_state_stree(stree, my_id, name, sym);
      253 +                if (get_state_stree(start_states, my_id, name, sym) == &inc)
      254 +                        goto swap_stree;
      255 +
      256 +                if (parent_is_gone_var_sym(name, sym))
      257 +                        goto swap_stree;
      258 +
      259 +                sm = get_sm_state(my_id, name, sym);
 173  260                  if (!sm)
 174      -                        continue;
      261 +                        goto swap_stree;
 175  262  
 176      -                if (sm->state != &inc && sm->state != &dec)
 177      -                        continue;
      263 +                if (sm->state != &inc &&
      264 +                    sm->state != &dec &&
      265 +                    sm->state != &orig)
      266 +                        goto swap_stree;
 178  267  
      268 +                bucket = success_fail_positive(estate_rl(return_sm->state));
      269 +
 179  270                  if (sm->state == &inc) {
 180  271                          add_range(&inc_lines, line, line);
 181      -                        inc_buckets[success_fail_positive(estate_rl(return_sm->state))] = 1;
      272 +                        inc_buckets[bucket] = true;
 182  273                  }
 183      -                if (sm->state == &dec)
      274 +                if (sm->state == &dec || sm->state == &orig) {
 184  275                          add_range(&dec_lines, line, line);
      276 +                        dec_buckets[bucket] = true;
      277 +                }
      278 +swap_stree:
      279 +                __swap_cur_stree(orig_stree);
 185  280          } END_FOR_EACH_PTR(stree);
 186  281  
 187  282          if (inc_buckets[NEGATIVE] &&
 188  283              inc_buckets[ZERO]) {
 189  284                  // sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
 190  285          }
 191  286  
 192  287  }
 193  288  
 194  289  static void match_check_missed(struct symbol *sym)
↓ open down ↓ 15 lines elided ↑ open up ↑
 210  305          } END_FOR_EACH_SM(sm);
 211  306  
 212  307          return 0;
 213  308  }
 214  309  
 215  310  int was_inced(const char *name, struct symbol *sym)
 216  311  {
 217  312          return get_state(my_id, name, sym) == &inc;
 218  313  }
 219  314  
      315 +static void match_save_states(struct expression *expr)
      316 +{
      317 +        push_stree(&saved_stack, start_states);
      318 +        start_states = NULL;
      319 +}
      320 +
      321 +static void match_restore_states(struct expression *expr)
      322 +{
      323 +        start_states = pop_stree(&saved_stack);
      324 +}
      325 +
      326 +static void match_after_func(struct symbol *sym)
      327 +{
      328 +        free_stree(&start_states);
      329 +}
      330 +
 220  331  void check_atomic_inc_dec(int id)
 221  332  {
 222  333          my_id = id;
 223  334  
 224  335          if (option_project != PROJ_KERNEL)
 225  336                  return;
 226  337  
      338 +        add_unmatched_state_hook(my_id, &unmatched_state);
      339 +
      340 +        add_split_return_callback(match_return_info);
 227  341          select_return_states_hook(ATOMIC_INC, &db_inc);
 228  342          select_return_states_hook(ATOMIC_DEC, &db_dec);
      343 +
 229  344          add_function_hook("atomic_inc_return", &match_atomic_inc, NULL);
 230  345          add_function_hook("atomic_add_return", &match_atomic_add, NULL);
 231  346          add_function_hook("atomic_sub_return", &match_atomic_sub, NULL);
 232  347          add_function_hook("atomic_sub_and_test", &match_atomic_sub, NULL);
 233  348          add_function_hook("atomic_dec_and_test", &match_atomic_dec, NULL);
 234  349          add_function_hook("_atomic_dec_and_lock", &match_atomic_dec, NULL);
 235  350          add_function_hook("atomic_dec", &match_atomic_dec, NULL);
 236  351          add_function_hook("atomic_long_inc", &match_atomic_inc, NULL);
 237  352          add_function_hook("atomic_long_dec", &match_atomic_dec, NULL);
 238  353          add_function_hook("atomic_inc", &match_atomic_inc, NULL);
 239  354          add_function_hook("atomic_sub", &match_atomic_sub, NULL);
 240      -        add_split_return_callback(match_return_info);
 241  355  
      356 +        add_function_hook("refcount_inc", &refcount_inc, INT_PTR(0));
      357 +        add_function_hook("refcount_dec", &refcount_dec, INT_PTR(0));
      358 +        add_function_hook("refcount_add", &refcount_inc, INT_PTR(1));
 242  359          add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1));
 243  360          add_function_hook("refcount_inc_not_zero", &refcount_inc, INT_PTR(0));
 244  361          add_function_hook("refcount_sub_and_test", &refcount_dec, INT_PTR(1));
 245      -        add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(1));
      362 +        add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(0));
 246  363  
 247  364          add_hook(&match_check_missed, END_FUNC_HOOK);
      365 +
      366 +        add_hook(&match_after_func, AFTER_FUNC_HOOK);
      367 +        add_hook(&match_save_states, INLINE_FN_START);
      368 +        add_hook(&match_restore_states, INLINE_FN_END);
 248  369  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX