Print this page
11506 smatch resync

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/smatch_slist.c
          +++ new/usr/src/tools/smatch/src/smatch_slist.c
↓ open down ↓ 88 lines elided ↑ open up ↑
  89   89  {
  90   90          int ret;
  91   91  
  92   92          if (a == b)
  93   93                  return 0;
  94   94          if (!b)
  95   95                  return -1;
  96   96          if (!a)
  97   97                  return 1;
  98   98  
  99      -        if (a->owner > b->owner)
 100      -                return -1;
 101   99          if (a->owner < b->owner)
      100 +                return -1;
      101 +        if (a->owner > b->owner)
 102  102                  return 1;
 103  103  
 104  104          ret = strcmp(a->name, b->name);
 105  105          if (ret < 0)
 106  106                  return -1;
 107  107          if (ret > 0)
 108  108                  return 1;
 109  109  
 110  110          if (!b->sym && a->sym)
 111  111                  return -1;
 112  112          if (!a->sym && b->sym)
 113  113                  return 1;
 114  114          if (a->sym < b->sym)
 115  115                  return -1;
 116  116          if (a->sym > b->sym)
 117  117                  return 1;
 118  118  
 119  119          return 0;
 120  120  }
 121  121  
 122      -static int cmp_sm_states(const struct sm_state *a, const struct sm_state *b, int preserve)
      122 +int *dynamic_states;
      123 +void allocate_dynamic_states_array(int num_checks)
 123  124  {
      125 +        dynamic_states = calloc(num_checks + 1, sizeof(int));
      126 +}
      127 +
      128 +void set_dynamic_states(unsigned short owner)
      129 +{
      130 +        dynamic_states[owner] = true;
      131 +}
      132 +
      133 +bool has_dynamic_states(unsigned short owner)
      134 +{
      135 +        if (owner >= num_checks)
      136 +                return false;
      137 +        return dynamic_states[owner];
      138 +}
      139 +
      140 +static int cmp_possible_sm(const struct sm_state *a, const struct sm_state *b, int preserve)
      141 +{
 124  142          int ret;
 125  143  
 126      -        ret = cmp_tracker(a, b);
 127      -        if (ret)
 128      -                return ret;
      144 +        if (a == b)
      145 +                return 0;
 129  146  
 130      -        /* todo:  add hook for smatch_extra.c */
 131      -        if (a->state > b->state)
 132      -                return -1;
 133      -        if (a->state < b->state)
 134      -                return 1;
 135      -        /* This is obviously a massive disgusting hack but we need to preserve
 136      -         * the unmerged states for smatch extra because we use them in
 137      -         * smatch_db.c.  Meanwhile if we preserve all the other unmerged states
 138      -         * then it uses a lot of memory and we don't use it.  Hence this hack.
 139      -         *
 140      -         * Also sometimes even just preserving every possible SMATCH_EXTRA state
 141      -         * takes too much resources so we have to cap that.  Capping is probably
 142      -         * not often a problem in real life.
 143      -         */
 144      -        if (a->owner == SMATCH_EXTRA && preserve) {
 145      -                if (a == b)
 146      -                        return 0;
 147      -                if (a->merged == 1 && b->merged == 0)
      147 +        if (!has_dynamic_states(a->owner)) {
      148 +                if (a->state > b->state)
 148  149                          return -1;
 149      -                if (a->merged == 0)
      150 +                if (a->state < b->state)
 150  151                          return 1;
      152 +                return 0;
 151  153          }
 152  154  
 153      -        return 0;
      155 +        if (a->owner == SMATCH_EXTRA) {
      156 +                /*
      157 +                 * In Smatch extra you can have borrowed implications.
      158 +                 *
      159 +                 * FIXME: review how borrowed implications work and if they
      160 +                 * are the best way.  See also smatch_implied.c.
      161 +                 *
      162 +                 */
      163 +                ret = cmp_tracker(a, b);
      164 +                if (ret)
      165 +                        return ret;
      166 +
      167 +                /*
      168 +                 * We want to preserve leaf states.  They're use to split
      169 +                 * returns in smatch_db.c.
      170 +                 *
      171 +                 */
      172 +                if (preserve) {
      173 +                        if (a->merged && !b->merged)
      174 +                                return -1;
      175 +                        if (!a->merged)
      176 +                                return 1;
      177 +                }
      178 +        }
      179 +        if (!a->state->name || !b->state->name)
      180 +                return 0;
      181 +
      182 +        return strcmp(a->state->name, b->state->name);
 154  183  }
 155  184  
 156  185  struct sm_state *alloc_sm_state(int owner, const char *name,
 157  186                                  struct symbol *sym, struct smatch_state *state)
 158  187  {
 159  188          struct sm_state *sm_state = __alloc_sm_state(0);
 160  189  
 161  190          sm_state_counter++;
 162  191  
 163  192          sm_state->name = alloc_sname(name);
 164  193          sm_state->owner = owner;
 165  194          sm_state->sym = sym;
 166  195          sm_state->state = state;
 167  196          sm_state->line = get_lineno();
 168  197          sm_state->merged = 0;
 169  198          sm_state->pool = NULL;
 170  199          sm_state->left = NULL;
 171  200          sm_state->right = NULL;
 172      -        sm_state->nr_children = 1;
 173  201          sm_state->possible = NULL;
 174  202          add_ptr_list(&sm_state->possible, sm_state);
 175  203          return sm_state;
 176  204  }
 177  205  
 178  206  static struct sm_state *alloc_state_no_name(int owner, const char *name,
 179  207                                       struct symbol *sym,
 180  208                                       struct smatch_state *state)
 181  209  {
 182  210          struct sm_state *tmp;
↓ open down ↓ 7 lines elided ↑ open up ↑
 190  218  {
 191  219          if (ptr_list_size((struct ptr_list *)sm->possible) >= 100)
 192  220                  return 1;
 193  221          return 0;
 194  222  }
 195  223  
 196  224  void add_possible_sm(struct sm_state *to, struct sm_state *new)
 197  225  {
 198  226          struct sm_state *tmp;
 199  227          int preserve = 1;
      228 +        int cmp;
 200  229  
 201  230          if (too_many_possible(to))
 202  231                  preserve = 0;
 203  232  
 204  233          FOR_EACH_PTR(to->possible, tmp) {
 205      -                if (cmp_sm_states(tmp, new, preserve) < 0)
      234 +                cmp = cmp_possible_sm(tmp, new, preserve);
      235 +                if (cmp < 0)
 206  236                          continue;
 207      -                else if (cmp_sm_states(tmp, new, preserve) == 0) {
      237 +                else if (cmp == 0) {
 208  238                          return;
 209  239                  } else {
 210  240                          INSERT_CURRENT(new, tmp);
 211  241                          return;
 212  242                  }
 213  243          } END_FOR_EACH_PTR(tmp);
 214  244          add_ptr_list(&to->possible, new);
 215  245  }
 216  246  
 217      -static void copy_possibles(struct sm_state *to, struct sm_state *from)
      247 +static void copy_possibles(struct sm_state *to, struct sm_state *one, struct sm_state *two)
 218  248  {
      249 +        struct sm_state *large = one;
      250 +        struct sm_state *small = two;
 219  251          struct sm_state *tmp;
 220  252  
 221      -        FOR_EACH_PTR(from->possible, tmp) {
      253 +        /*
      254 +         * We spend a lot of time copying the possible lists.  I've tried to
      255 +         * optimize the process a bit.
      256 +         *
      257 +         */
      258 +
      259 +        if (ptr_list_size((struct ptr_list *)two->possible) >
      260 +            ptr_list_size((struct ptr_list *)one->possible)) {
      261 +                large = two;
      262 +                small = one;
      263 +        }
      264 +
      265 +        to->possible = clone_slist(large->possible);
      266 +        add_possible_sm(to, to);
      267 +        FOR_EACH_PTR(small->possible, tmp) {
 222  268                  add_possible_sm(to, tmp);
 223  269          } END_FOR_EACH_PTR(tmp);
 224  270  }
 225  271  
 226  272  char *alloc_sname(const char *str)
 227  273  {
 228  274          char *tmp;
 229  275  
 230  276          if (!str)
 231  277                  return NULL;
 232  278          tmp = __alloc_sname(strlen(str) + 1);
 233  279          strcpy(tmp, str);
 234  280          return tmp;
 235  281  }
 236  282  
      283 +static struct symbol *oom_func;
      284 +static int oom_limit = 3000000;  /* Start with a 3GB limit */
 237  285  int out_of_memory(void)
 238  286  {
      287 +        if (oom_func)
      288 +                return 1;
      289 +
 239  290          /*
 240  291           * I decided to use 50M here based on trial and error.
 241  292           * It works out OK for the kernel and so it should work
 242  293           * for most other projects as well.
 243  294           */
 244  295          if (sm_state_counter * sizeof(struct sm_state) >= 100000000)
 245  296                  return 1;
      297 +
      298 +        /*
      299 +         * We're reading from statm to figure out how much memory we
      300 +         * are using.  The problem is that at the end of the function
      301 +         * we release the memory, so that it can be re-used but it
      302 +         * stays in cache, it's not released to the OS.  So then if
      303 +         * we allocate memory for different purposes we can easily
      304 +         * hit the 3GB limit on the next function, so that's why I give
      305 +         * the next function an extra 100MB to work with.
      306 +         *
      307 +         */
      308 +        if (get_mem_kb() > oom_limit) {
      309 +                oom_func = cur_func_sym;
      310 +                final_pass++;
      311 +                sm_perror("OOM: %luKb sm_state_count = %d", get_mem_kb(), sm_state_counter);
      312 +                final_pass--;
      313 +                return 1;
      314 +        }
      315 +
 246  316          return 0;
 247  317  }
 248  318  
 249  319  int low_on_memory(void)
 250  320  {
 251  321          if (sm_state_counter * sizeof(struct sm_state) >= 25000000)
 252  322                  return 1;
 253  323          return 0;
 254  324  }
 255  325  
↓ open down ↓ 34 lines elided ↑ open up ↑
 290  360                  struct allocation_blob *next = blob->next;
 291  361                  free_all_sm_states(blob);
 292  362                  blob_free(blob, desc->chunking);
 293  363                  blob = next;
 294  364          }
 295  365          clear_sname_alloc();
 296  366          clear_smatch_state_alloc();
 297  367  
 298  368          free_stack_and_strees(&all_pools);
 299  369          sm_state_counter = 0;
      370 +        if (oom_func) {
      371 +                oom_limit += 100000;
      372 +                oom_func = NULL;
      373 +        }
 300  374  }
 301  375  
 302  376  unsigned long get_pool_count(void)
 303  377  {
 304  378          return ptr_list_size((struct ptr_list *)all_pools);
 305  379  }
 306  380  
 307  381  struct sm_state *clone_sm(struct sm_state *s)
 308  382  {
 309  383          struct sm_state *ret;
 310  384  
 311  385          ret = alloc_state_no_name(s->owner, s->name, s->sym, s->state);
 312  386          ret->merged = s->merged;
 313  387          ret->line = s->line;
 314  388          /* clone_sm() doesn't copy the pools.  Each state needs to have
 315  389             only one pool. */
 316  390          ret->possible = clone_slist(s->possible);
 317  391          ret->left = s->left;
 318  392          ret->right = s->right;
 319      -        ret->nr_children = s->nr_children;
 320  393          return ret;
 321  394  }
 322  395  
 323  396  int is_merged(struct sm_state *sm)
 324  397  {
 325  398          return sm->merged;
 326  399  }
 327  400  
 328  401  int is_leaf(struct sm_state *sm)
 329  402  {
↓ open down ↓ 57 lines elided ↑ open up ↑
 387  460                          sm_warning("Function too hairy.  No more merges.");
 388  461                  warned = 1;
 389  462                  return one;
 390  463          }
 391  464          warned = 0;
 392  465          s = merge_states(one->owner, one->name, one->sym, one->state, two->state);
 393  466          result = alloc_state_no_name(one->owner, one->name, one->sym, s);
 394  467          result->merged = 1;
 395  468          result->left = one;
 396  469          result->right = two;
 397      -        result->nr_children = one->nr_children + two->nr_children;
 398      -        copy_possibles(result, one);
 399      -        copy_possibles(result, two);
 400  470  
      471 +        copy_possibles(result, one, two);
      472 +
 401  473          /*
 402  474           * The ->line information is used by deref_check where we complain about
 403  475           * checking pointers that have already been dereferenced.  Let's say we
 404  476           * dereference a pointer on both the true and false paths and then merge
 405  477           * the states here.  The result state is &derefed, but the ->line number
 406  478           * is on the line where the pointer is merged not where it was
 407  479           * dereferenced..
 408  480           *
 409  481           * So in that case, let's just pick one dereference and set the ->line
 410  482           * to point at it.
↓ open down ↓ 300 lines elided ↑ open up ↑
 711  783   * merge_slist() is called whenever paths merge, such as after
 712  784   * an if statement.  It takes the two slists and creates one.
 713  785   */
 714  786  static void __merge_stree(struct stree **to, struct stree *stree, int add_pool)
 715  787  {
 716  788          struct stree *results = NULL;
 717  789          struct stree *implied_one = NULL;
 718  790          struct stree *implied_two = NULL;
 719  791          AvlIter one_iter;
 720  792          AvlIter two_iter;
 721      -        struct sm_state *tmp_sm;
      793 +        struct sm_state *one, *two, *res;
 722  794  
 723  795          if (out_of_memory())
 724  796                  return;
 725  797  
 726  798          /* merging a null and nonnull path gives you only the nonnull path */
 727  799          if (!stree)
 728  800                  return;
 729  801          if (*to == stree)
 730  802                  return;
 731  803  
↓ open down ↓ 22 lines elided ↑ open up ↑
 754  826  
 755  827          push_stree(&all_pools, implied_one);
 756  828          push_stree(&all_pools, implied_two);
 757  829  
 758  830          avl_iter_begin(&one_iter, implied_one, FORWARD);
 759  831          avl_iter_begin(&two_iter, implied_two, FORWARD);
 760  832  
 761  833          for (;;) {
 762  834                  if (!one_iter.sm || !two_iter.sm)
 763  835                          break;
 764      -                if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
 765      -                        sm_perror(" in %s", __func__);
 766      -                        avl_iter_next(&one_iter);
 767      -                } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
 768      -                        if (add_pool && one_iter.sm != two_iter.sm) {
 769      -                                one_iter.sm->pool = implied_one;
 770      -                                if (implied_one->base_stree)
 771      -                                        one_iter.sm->pool = implied_one->base_stree;
 772      -                                two_iter.sm->pool = implied_two;
 773      -                                if (implied_two->base_stree)
 774      -                                        two_iter.sm->pool = implied_two->base_stree;
 775      -                        }
 776      -                        tmp_sm = merge_sm_states(one_iter.sm, two_iter.sm);
 777      -                        add_possible_sm(tmp_sm, one_iter.sm);
 778      -                        add_possible_sm(tmp_sm, two_iter.sm);
 779      -                        avl_insert(&results, tmp_sm);
 780      -                        avl_iter_next(&one_iter);
 781      -                        avl_iter_next(&two_iter);
 782      -                } else {
 783      -                        sm_perror(" in %s", __func__);
 784      -                        avl_iter_next(&two_iter);
      836 +
      837 +                one = one_iter.sm;
      838 +                two = two_iter.sm;
      839 +
      840 +                if (one == two) {
      841 +                        avl_insert(&results, one);
      842 +                        goto next;
 785  843                  }
      844 +
      845 +                if (add_pool) {
      846 +                        one->pool = implied_one;
      847 +                        if (implied_one->base_stree)
      848 +                                one->pool = implied_one->base_stree;
      849 +                        two->pool = implied_two;
      850 +                        if (implied_two->base_stree)
      851 +                                two->pool = implied_two->base_stree;
      852 +                }
      853 +                res = merge_sm_states(one, two);
      854 +                add_possible_sm(res, one);
      855 +                add_possible_sm(res, two);
      856 +                avl_insert(&results, res);
      857 +next:
      858 +                avl_iter_next(&one_iter);
      859 +                avl_iter_next(&two_iter);
 786  860          }
 787  861  
 788  862          free_stree(to);
 789  863          *to = results;
 790  864  }
 791  865  
 792  866  void merge_stree(struct stree **to, struct stree *stree)
 793  867  {
 794  868          __merge_stree(to, stree, 1);
 795  869  }
↓ open down ↓ 199 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX