Print this page
12826 update to smatch 0.6.1-rc1-il-6

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 ↓ 16 lines elided ↑ open up ↑
  17   17  
  18   18  #include <ctype.h>
  19   19  
  20   20  #include "smatch.h"
  21   21  #include "smatch_extra.h"
  22   22  #include "smatch_slist.h"
  23   23  
  24   24  static int my_id;
  25   25  
  26   26  STATE(inc);
  27      -STATE(orig);
       27 +STATE(start_state);
  28   28  STATE(dec);
  29   29  
  30   30  static struct smatch_state *unmatched_state(struct sm_state *sm)
  31   31  {
  32      -        if (parent_is_gone_var_sym(sm->name, sm->sym))
       32 +        /*
       33 +         * We default to decremented.  For example, say we have:
       34 +         *      if (p)
       35 +         *              atomic_dec(p);
       36 +         *      <- p is decreemented.
       37 +         *
       38 +         */
       39 +        if ((sm->state == &dec) &&
       40 +            parent_is_gone_var_sym(sm->name, sm->sym))
  33   41                  return sm->state;
  34      -        return &undefined;
       42 +        return &start_state;
  35   43  }
  36   44  
  37   45  static struct stree *start_states;
  38   46  static struct stree_stack *saved_stack;
  39   47  static void set_start_state(const char *name, struct symbol *sym, struct smatch_state *start)
  40   48  {
  41   49          struct smatch_state *orig;
  42   50  
  43   51          orig = get_state_stree(start_states, my_id, name, sym);
  44   52          if (!orig)
↓ open down ↓ 34 lines elided ↑ open up ↑
  79   87                          cnt++;
  80   88                          match = sm;
  81   89                  }
  82   90          } END_FOR_EACH_SM(sm);
  83   91  
  84   92          if (cnt == 1)
  85   93                  return match;
  86   94          return NULL;
  87   95  }
  88   96  
  89      -static void db_inc_dec(struct expression *expr, int param, const char *key, const char *value, int inc_dec)
       97 +static void db_inc_dec(struct expression *expr, int param, const char *key, int inc_dec)
  90   98  {
  91   99          struct sm_state *start_sm;
  92  100          struct expression *arg;
  93  101          char *name;
  94  102          struct symbol *sym;
  95  103          bool free_at_end = true;
  96  104  
  97  105          while (expr->type == EXPR_ASSIGNMENT)
  98  106                  expr = strip_expr(expr->right);
  99  107          if (expr->type != EXPR_CALL)
↓ open down ↓ 22 lines elided ↑ open up ↑
 122  130                  if (!start_sm)
 123  131                          set_start_state(name, sym, &dec);
 124  132  //              set_refcount_inc(name, sym);
 125  133                  set_state(my_id, name, sym, &inc);
 126  134          } else {
 127  135  //              set_refcount_dec(name, sym);
 128  136                  if (!start_sm)
 129  137                          set_start_state(name, sym, &inc);
 130  138  
 131  139                  if (start_sm && start_sm->state == &inc)
 132      -                        set_state(my_id, name, sym, &orig);
      140 +                        set_state(my_id, name, sym, &start_state);
 133  141                  else
 134  142                          set_state(my_id, name, sym, &dec);
 135  143          }
 136  144  
 137  145  free:
 138  146          if (free_at_end)
 139  147                  free_string(name);
 140  148  }
 141  149  
      150 +static const char *primitive_funcs[] = {
      151 +        "atomic_inc_return",
      152 +        "atomic_add_return",
      153 +        "atomic_sub_return",
      154 +        "atomic_sub_and_test",
      155 +        "atomic_dec_and_test",
      156 +        "_atomic_dec_and_lock",
      157 +        "atomic_dec",
      158 +        "atomic_long_inc",
      159 +        "atomic_long_dec",
      160 +        "atomic_inc",
      161 +        "atomic_sub",
      162 +        "refcount_inc",
      163 +        "refcount_dec",
      164 +        "refcount_add",
      165 +        "refcount_add_not_zero",
      166 +        "refcount_inc_not_zero",
      167 +        "refcount_sub_and_test",
      168 +        "refcount_dec_and_test",
      169 +        "atomic_dec_if_positive",
      170 +};
      171 +
      172 +static bool is_inc_dec_primitive(struct expression *expr)
      173 +{
      174 +        int i;
      175 +
      176 +        while (expr->type == EXPR_ASSIGNMENT)
      177 +                expr = strip_expr(expr->right);
      178 +        if (expr->type != EXPR_CALL)
      179 +                return false;
      180 +
      181 +        if (expr->fn->type != EXPR_SYMBOL)
      182 +                return false;
      183 +
      184 +        for (i = 0; i < ARRAY_SIZE(primitive_funcs); i++) {
      185 +                if (sym_name_is(primitive_funcs[i], expr->fn))
      186 +                        return true;
      187 +        }
      188 +
      189 +        return false;
      190 +}
      191 +
 142  192  static void db_inc(struct expression *expr, int param, char *key, char *value)
 143  193  {
 144      -        db_inc_dec(expr, param, key, value, ATOMIC_INC);
      194 +        if (is_inc_dec_primitive(expr))
      195 +                return;
      196 +        db_inc_dec(expr, param, key, ATOMIC_INC);
 145  197  }
 146  198  
 147  199  static void db_dec(struct expression *expr, int param, char *key, char *value)
 148  200  {
 149      -        db_inc_dec(expr, param, key, value, ATOMIC_DEC);
      201 +        if (is_inc_dec_primitive(expr))
      202 +                return;
      203 +        db_inc_dec(expr, param, key, ATOMIC_DEC);
 150  204  }
 151  205  
 152  206  static void match_atomic_inc(const char *fn, struct expression *expr, void *_unused)
 153  207  {
 154      -        db_inc_dec(expr, 0, "$->counter", "", ATOMIC_INC);
      208 +        db_inc_dec(expr, 0, "$->counter", ATOMIC_INC);
 155  209  }
 156  210  
 157  211  static void match_atomic_dec(const char *fn, struct expression *expr, void *_unused)
 158  212  {
 159      -        db_inc_dec(expr, 0, "$->counter", "", ATOMIC_DEC);
      213 +        db_inc_dec(expr, 0, "$->counter", ATOMIC_DEC);
 160  214  }
 161  215  
 162  216  static void match_atomic_add(const char *fn, struct expression *expr, void *_unused)
 163  217  {
 164  218          struct expression *amount;
 165  219          sval_t sval;
 166  220  
 167  221          amount = get_argument_from_call_expr(expr->args, 0);
 168  222          if (get_implied_value(amount, &sval) && sval_is_negative(sval)) {
 169      -                db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
      223 +                db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC);
 170  224                  return;
 171  225          }
 172  226  
 173      -        db_inc_dec(expr, 1, "$->counter", "", ATOMIC_INC);
      227 +        db_inc_dec(expr, 1, "$->counter", ATOMIC_INC);
 174  228  }
 175  229  
 176  230  static void match_atomic_sub(const char *fn, struct expression *expr, void *_unused)
 177  231  {
 178      -        db_inc_dec(expr, 1, "$->counter", "", ATOMIC_DEC);
      232 +        db_inc_dec(expr, 1, "$->counter", ATOMIC_DEC);
 179  233  }
 180  234  
 181  235  static void refcount_inc(const char *fn, struct expression *expr, void *param)
 182  236  {
 183      -        db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_INC);
      237 +        db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC);
 184  238  }
 185  239  
 186  240  static void refcount_dec(const char *fn, struct expression *expr, void *param)
 187  241  {
 188      -        db_inc_dec(expr, PTR_INT(param), "$->ref.counter", "", ATOMIC_DEC);
      242 +        db_inc_dec(expr, PTR_INT(param), "$->ref.counter", ATOMIC_DEC);
 189  243  }
 190  244  
      245 +static void pm_runtime_get_sync(const char *fn, struct expression *expr, void *param)
      246 +{
      247 +        db_inc_dec(expr, PTR_INT(param), "$->power.usage_count.counter", ATOMIC_INC);
      248 +}
      249 +
      250 +static void match_implies_inc(const char *fn, struct expression *call_expr,
      251 +                              struct expression *assign_expr, void *param)
      252 +{
      253 +        db_inc_dec(call_expr, PTR_INT(param), "$->ref.counter", ATOMIC_INC);
      254 +}
      255 +
      256 +static void match_implies_atomic_dec(const char *fn, struct expression *call_expr,
      257 +                              struct expression *assign_expr, void *param)
      258 +{
      259 +        db_inc_dec(call_expr, PTR_INT(param), "$->counter", ATOMIC_DEC);
      260 +}
      261 +
      262 +static bool is_maybe_dec(struct sm_state *sm)
      263 +{
      264 +        if (sm->state == &dec)
      265 +                return true;
      266 +        if (slist_has_state(sm->possible, &dec) &&
      267 +            !slist_has_state(sm->possible, &inc))
      268 +                return true;
      269 +        return false;
      270 +}
      271 +
 191  272  static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
 192  273  {
 193  274          struct sm_state *sm;
 194  275          const char *param_name;
 195  276          int param;
 196  277  
      278 +        if (is_impossible_path())
      279 +                return;
      280 +
 197  281          FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
 198      -                if (sm->state != &inc &&
 199      -                    sm->state != &dec)
      282 +                if (sm->state != &inc && !is_maybe_dec(sm))
 200  283                          continue;
      284 +                if (sm->state == get_state_stree(start_states, my_id, sm->name, sm->sym))
      285 +                        continue;
 201  286                  if (parent_is_gone_var_sym(sm->name, sm->sym))
 202  287                          continue;
 203  288                  param = get_param_num_from_sym(sm->sym);
 204  289                  if (param < 0)
 205  290                          continue;
 206  291                  param_name = get_param_name(sm);
 207  292                  if (!param_name)
 208  293                          continue;
 209  294                  sql_insert_return_states(return_id, return_ranges,
 210  295                                           (sm->state == &inc) ? ATOMIC_INC : ATOMIC_DEC,
↓ open down ↓ 3 lines elided ↑ open up ↑
 214  299  
 215  300  enum {
 216  301          EMPTY, NEGATIVE, ZERO, POSITIVE, NUM_BUCKETS
 217  302  };
 218  303  
 219  304  static int success_fail_positive(struct range_list *rl)
 220  305  {
 221  306          if (!rl)
 222  307                  return EMPTY;
 223  308  
 224      -        if (sval_is_negative(rl_min(rl)))
      309 +        if (!is_whole_rl(rl) && sval_is_negative(rl_min(rl)))
 225  310                  return NEGATIVE;
 226  311  
 227  312          if (rl_min(rl).value == 0)
 228  313                  return ZERO;
 229  314  
 230  315          return POSITIVE;
 231  316  }
 232  317  
 233  318  static void check_counter(const char *name, struct symbol *sym)
 234  319  {
 235  320          struct range_list *inc_lines = NULL;
 236  321          struct range_list *dec_lines = NULL;
 237  322          int inc_buckets[NUM_BUCKETS] = {};
 238  323          int dec_buckets[NUM_BUCKETS] = {};
 239  324          struct stree *stree, *orig_stree;
      325 +        struct smatch_state *state;
 240  326          struct sm_state *return_sm;
 241  327          struct sm_state *sm;
 242  328          sval_t line = sval_type_val(&int_ctype, 0);
 243  329          int bucket;
 244  330  
      331 +        /* static variable are probably just counters */
      332 +        if (sym->ctype.modifiers & MOD_STATIC &&
      333 +            !(sym->ctype.modifiers & MOD_TOPLEVEL))
      334 +                return;
      335 +
 245  336          FOR_EACH_PTR(get_all_return_strees(), stree) {
 246  337                  orig_stree = __swap_cur_stree(stree);
 247  338  
      339 +                if (is_impossible_path())
      340 +                        goto swap_stree;
      341 +
 248  342                  return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
 249  343                  if (!return_sm)
 250  344                          goto swap_stree;
 251  345                  line.value = return_sm->line;
 252  346  
 253  347                  if (get_state_stree(start_states, my_id, name, sym) == &inc)
 254  348                          goto swap_stree;
 255  349  
 256  350                  if (parent_is_gone_var_sym(name, sym))
 257  351                          goto swap_stree;
 258  352  
 259  353                  sm = get_sm_state(my_id, name, sym);
 260      -                if (!sm)
 261      -                        goto swap_stree;
      354 +                if (sm)
      355 +                        state = sm->state;
      356 +                else
      357 +                        state = &start_state;
 262  358  
 263      -                if (sm->state != &inc &&
 264      -                    sm->state != &dec &&
 265      -                    sm->state != &orig)
      359 +                if (state != &inc &&
      360 +                    state != &dec &&
      361 +                    state != &start_state)
 266  362                          goto swap_stree;
 267  363  
 268  364                  bucket = success_fail_positive(estate_rl(return_sm->state));
 269  365  
 270      -                if (sm->state == &inc) {
      366 +                if (state == &inc) {
 271  367                          add_range(&inc_lines, line, line);
 272  368                          inc_buckets[bucket] = true;
 273  369                  }
 274      -                if (sm->state == &dec || sm->state == &orig) {
      370 +                if (state == &dec || state == &start_state) {
 275  371                          add_range(&dec_lines, line, line);
 276  372                          dec_buckets[bucket] = true;
 277  373                  }
 278  374  swap_stree:
 279  375                  __swap_cur_stree(orig_stree);
 280  376          } END_FOR_EACH_PTR(stree);
 281  377  
 282  378          if (inc_buckets[NEGATIVE] &&
 283  379              inc_buckets[ZERO]) {
 284  380                  // sm_warning("XXX '%s' not decremented on lines: %s.", name, show_rl(inc_lines));
↓ open down ↓ 53 lines elided ↑ open up ↑
 338  434          add_unmatched_state_hook(my_id, &unmatched_state);
 339  435  
 340  436          add_split_return_callback(match_return_info);
 341  437          select_return_states_hook(ATOMIC_INC, &db_inc);
 342  438          select_return_states_hook(ATOMIC_DEC, &db_dec);
 343  439  
 344  440          add_function_hook("atomic_inc_return", &match_atomic_inc, NULL);
 345  441          add_function_hook("atomic_add_return", &match_atomic_add, NULL);
 346  442          add_function_hook("atomic_sub_return", &match_atomic_sub, NULL);
 347  443          add_function_hook("atomic_sub_and_test", &match_atomic_sub, NULL);
      444 +        add_function_hook("atomic_long_sub_and_test", &match_atomic_sub, NULL);
      445 +        add_function_hook("atomic64_sub_and_test", &match_atomic_sub, NULL);
 348  446          add_function_hook("atomic_dec_and_test", &match_atomic_dec, NULL);
      447 +        add_function_hook("atomic_long_dec_and_test", &match_atomic_dec, NULL);
      448 +        add_function_hook("atomic64_dec_and_test", &match_atomic_dec, NULL);
 349  449          add_function_hook("_atomic_dec_and_lock", &match_atomic_dec, NULL);
 350  450          add_function_hook("atomic_dec", &match_atomic_dec, NULL);
      451 +        add_function_hook("atomic_dec_return", &match_atomic_dec, NULL);
 351  452          add_function_hook("atomic_long_inc", &match_atomic_inc, NULL);
 352  453          add_function_hook("atomic_long_dec", &match_atomic_dec, NULL);
 353  454          add_function_hook("atomic_inc", &match_atomic_inc, NULL);
 354  455          add_function_hook("atomic_sub", &match_atomic_sub, NULL);
 355  456  
 356  457          add_function_hook("refcount_inc", &refcount_inc, INT_PTR(0));
 357  458          add_function_hook("refcount_dec", &refcount_dec, INT_PTR(0));
 358  459          add_function_hook("refcount_add", &refcount_inc, INT_PTR(1));
 359      -        add_function_hook("refcount_add_not_zero", &refcount_inc, INT_PTR(1));
 360      -        add_function_hook("refcount_inc_not_zero", &refcount_inc, INT_PTR(0));
      460 +
      461 +        return_implies_state("refcount_add_not_zero", 1, 1, &match_implies_inc, INT_PTR(1));
      462 +        return_implies_state("refcount_inc_not_zero", 1, 1, &match_implies_inc, INT_PTR(0));
      463 +
      464 +        return_implies_state("atomic_dec_if_positive", 0, INT_MAX, &match_implies_atomic_dec, INT_PTR(0));
      465 +
 361  466          add_function_hook("refcount_sub_and_test", &refcount_dec, INT_PTR(1));
 362  467          add_function_hook("refcount_dec_and_test", &refcount_dec, INT_PTR(0));
 363  468  
      469 +        add_function_hook("pm_runtime_get_sync", &pm_runtime_get_sync, INT_PTR(0));
      470 +
 364  471          add_hook(&match_check_missed, END_FUNC_HOOK);
 365  472  
 366  473          add_hook(&match_after_func, AFTER_FUNC_HOOK);
 367  474          add_hook(&match_save_states, INLINE_FN_START);
 368  475          add_hook(&match_restore_states, INLINE_FN_END);
 369  476  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX