Print this page
11506 smatch resync

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/smatch_container_of.c
          +++ new/usr/src/tools/smatch/src/smatch_container_of.c
↓ open down ↓ 104 lines elided ↑ open up ↑
 105  105  
 106  106          if (!sym || !sym->ident)
 107  107                  return -1;
 108  108  
 109  109          __mptr = get_assigned_expr_name_sym(sym->ident->name, sym);
 110  110          offset = get_offset_from_container_of(__mptr);
 111  111  
 112  112          return offset;
 113  113  }
 114  114  
 115      -static char *get_container_name(struct sm_state *sm, int offset)
      115 +static char *get_container_name_sm(struct sm_state *sm, int offset)
 116  116  {
 117  117          static char buf[256];
 118  118          const char *name;
 119  119  
 120  120          name = get_param_name(sm);
 121  121          if (!name)
 122  122                  return NULL;
 123  123  
 124  124          if (name[0] == '$')
 125  125                  snprintf(buf, sizeof(buf), "$(-%d)%s", offset, name + 1);
↓ open down ↓ 40 lines elided ↑ open up ↑
 166  166  {
 167  167          struct sm_state *tmp;
 168  168          int arg, offset;
 169  169          const char *name;
 170  170  
 171  171          FOR_EACH_SM(used_stree, tmp) {
 172  172                  arg = get_container_arg(tmp->sym);
 173  173                  offset = get_container_offset(tmp->sym);
 174  174                  if (arg < 0 || offset < 0)
 175  175                          continue;
 176      -                name = get_container_name(tmp, offset);
      176 +                name = get_container_name_sm(tmp, offset);
 177  177                  if (!name)
 178  178                          continue;
 179  179                  sql_insert_return_implies(CONTAINER, arg, name, "");
 180  180          } END_FOR_EACH_SM(tmp);
 181  181  
 182  182          free_stree(&used_stree);
 183  183  }
 184  184  
 185  185  static void match_function_def(struct symbol *sym)
 186  186  {
↓ open down ↓ 55 lines elided ↑ open up ↑
 242  242                  return;
 243  243          if (arg->type != EXPR_SYMBOL)
 244  244                  return;
 245  245          param = get_param_num(arg);
 246  246          if (param < 0)
 247  247                  return;
 248  248          snprintf(buf, sizeof(buf), "$(%d)", offset);
 249  249          sql_insert_return_implies(CONTAINER, param, buf, "");
 250  250  }
 251  251  
 252      -static int get_shared_cnt(const char *one, const char *two)
      252 +static int get_deref_count(struct expression *expr)
 253  253  {
 254      -        int i;
 255      -        int on_end = false;
      254 +        int cnt = 0;
 256  255  
 257      -        i = 0;
 258      -        while (true) {
 259      -                if (!one[i] || !two[i]) {
 260      -                        on_end = true;
 261      -                        break;
 262      -                }
 263      -                if (one[i] != two[i])
 264      -                        break;
 265      -                i++;
      256 +        while (expr && expr->type == EXPR_DEREF) {
      257 +                expr = expr->deref;
      258 +                if (expr->type == EXPR_PREOP && expr->op == '*')
      259 +                        expr = expr->unop;
      260 +                cnt++;
      261 +                if (cnt > 100)
      262 +                        return -1;
 266  263          }
 267      -        if (i == 0)
 268      -                return 0;
 269      -        i--;
 270      -        while (i > 0 && (one[i] == '>' || one[i] == '-' || one[i] == '.')) {
 271      -                on_end = true;
 272      -                i--;
      264 +        return cnt;
      265 +}
      266 +
      267 +static struct expression *get_partial_deref(struct expression *expr, int cnt)
      268 +{
      269 +        while (--cnt >= 0) {
      270 +                if (!expr || expr->type != EXPR_DEREF)
      271 +                        return expr;
      272 +                expr = expr->deref;
      273 +                if (expr->type == EXPR_PREOP && expr->op == '*')
      274 +                        expr = expr->unop;
 273  275          }
 274      -        if (!on_end)
 275      -                return 0;
      276 +        return expr;
      277 +}
 276  278  
 277      -        return i + 1;
      279 +static int partial_deref_to_offset_str(struct expression *expr, int cnt, char op, char *buf, int size)
      280 +{
      281 +        int n, offset;
      282 +
      283 +        if (cnt == 0)
      284 +                return snprintf(buf, size, "%c0", op);
      285 +
      286 +        n = 0;
      287 +        while (--cnt >= 0) {
      288 +                offset = get_member_offset_from_deref(expr);
      289 +                if (offset < 0)
      290 +                        return -1;
      291 +                n += snprintf(buf + n, size - n, "%c%d", op, offset);
      292 +                if (expr->type != EXPR_DEREF)
      293 +                        return -1;
      294 +                expr = expr->deref;
      295 +                if (expr->type == EXPR_PREOP && expr->op == '*')
      296 +                        expr = expr->unop;
      297 +        }
      298 +
      299 +        return n;
 278  300  }
 279  301  
 280      -static int build_offset_str(struct expression *expr, const char *name,
 281      -                            int shared, char *buf, int size, int op)
      302 +static char *get_shared_str(struct expression *container, struct expression *expr)
 282  303  {
 283      -        int chop = 0;
 284      -        int offset;
 285      -        int i;
      304 +        struct expression *one, *two;
      305 +        int cont, exp, min, ret, n;
      306 +        static char buf[48];
 286  307  
 287      -        i = shared;
 288      -        while (name[i]) {
 289      -                if (name[i] == '.' || name[i] == '-')
 290      -                        chop++;
 291      -                i++;
      308 +        cont = get_deref_count(container);
      309 +        exp = get_deref_count(expr);
      310 +        if (cont < 0 || exp < 0)
      311 +                return NULL;
      312 +
      313 +        min = (cont < exp) ? cont : exp;
      314 +        while (min >= 0) {
      315 +                one = get_partial_deref(container, cont - min);
      316 +                two = get_partial_deref(expr, exp - min);
      317 +                if (expr_equiv(one, two))
      318 +                        goto found;
      319 +                min--;
 292  320          }
 293  321  
 294      -        // FIXME:  Handle more chops
 295      -        if (chop > 1)
 296      -                return 0;
      322 +        return NULL;
 297  323  
 298      -        if (chop == 0) {
 299      -                offset = 0;
 300      -        } else {
 301      -                offset = get_member_offset_from_deref(expr);
 302      -                if (offset < 0)
 303      -                        return 0;
      324 +found:
      325 +        ret = partial_deref_to_offset_str(container, cont - min, '-', buf, sizeof(buf));
      326 +        if (ret < 0)
      327 +                return NULL;
      328 +        n = ret;
      329 +        ret = partial_deref_to_offset_str(expr, exp - min, '+', buf + ret, sizeof(buf) - ret);
      330 +        if (ret < 0)
      331 +                return NULL;
      332 +        n += ret;
      333 +        if (n >= sizeof(buf))
      334 +                return NULL;
      335 +
      336 +        return buf;
      337 +}
      338 +
      339 +char *get_container_name(struct expression *container, struct expression *expr)
      340 +{
      341 +        struct symbol *container_sym, *sym;
      342 +        struct expression *tmp;
      343 +        static char buf[64];
      344 +        char *shared;
      345 +        bool star;
      346 +        int cnt;
      347 +
      348 +        container_sym = expr_to_sym(container);
      349 +        sym = expr_to_sym(expr);
      350 +        if (container_sym && container_sym == sym)
      351 +                goto found;
      352 +
      353 +        cnt = 0;
      354 +        while ((tmp = get_assigned_expr(expr))) {
      355 +                expr = tmp;
      356 +                if (cnt++ > 3)
      357 +                        break;
 304  358          }
 305  359  
 306      -        snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset);
 307      -        return 1;
      360 +        cnt = 0;
      361 +        while ((tmp = get_assigned_expr(container))) {
      362 +                container = tmp;
      363 +                if (cnt++ > 3)
      364 +                        break;
      365 +        }
      366 +
      367 +found:
      368 +        expr = strip_expr(expr);
      369 +        star = true;
      370 +        if (expr->type == EXPR_PREOP && expr->op == '&') {
      371 +                expr = strip_expr(expr->unop);
      372 +                star = false;
      373 +        }
      374 +
      375 +        container_sym = expr_to_sym(container);
      376 +        if (!container_sym)
      377 +                return NULL;
      378 +        sym = expr_to_sym(expr);
      379 +        if (!sym || container_sym != sym)
      380 +                return NULL;
      381 +
      382 +        shared = get_shared_str(container, expr);
      383 +        if (star)
      384 +                snprintf(buf, sizeof(buf), "*(%s)", shared);
      385 +        else
      386 +                snprintf(buf, sizeof(buf), "%s", shared);
      387 +
      388 +        return buf;
 308  389  }
 309  390  
 310  391  static void match_call(struct expression *call)
 311  392  {
 312  393          struct expression *fn, *arg;
 313      -        char *fn_name, *arg_name;
 314      -        int param, shared;
 315      -        char minus_str[64];
 316      -        char plus_str[64];
 317      -        char offset_str[64];
 318      -        bool star;
      394 +        char *name;
      395 +        int param;
 319  396  
 320  397          /*
 321  398           * We're trying to link the function with the parameter.  There are a
 322  399           * couple ways this can be passed:
 323  400           * foo->func(foo, ...);
 324  401           * foo->func(foo->x, ...);
 325  402           * foo->bar.func(&foo->bar, ...);
 326  403           * foo->bar->baz->func(foo, ...);
 327  404           *
 328  405           * So the method is basically to subtract the offsets until we get to
 329  406           * the common bit, then add the member offsets to get the parameter.
 330  407           *
 331  408           * If we're taking an address then the offset math is not stared,
 332  409           * otherwise it is.  Starred means dereferenced.
 333  410           */
 334  411          fn = strip_expr(call->fn);
 335      -        fn_name = expr_to_var(fn);
 336      -        if (!fn_name)
 337      -                return;
 338  412  
 339  413          param = -1;
 340  414          FOR_EACH_PTR(call->args, arg) {
 341  415                  param++;
 342  416  
 343      -                arg = strip_expr(arg);
 344      -                star = true;
 345      -                if (arg->type == EXPR_PREOP && arg->op == '&') {
 346      -                        arg = strip_expr(arg->unop);
 347      -                        star = false;
 348      -                }
 349      -
 350      -                arg_name = expr_to_var(arg);
 351      -                if (!arg_name)
      417 +                name = get_container_name(fn, arg);
      418 +                if (!name)
 352  419                          continue;
 353      -                shared = get_shared_cnt(fn_name, arg_name);
 354      -                if (!shared)
 355      -                        goto free_arg_name;
 356      -                if (!build_offset_str(fn, fn_name, shared, minus_str, sizeof(minus_str), '-'))
 357      -                        goto free_arg_name;
 358      -                if (!build_offset_str(arg, arg_name, shared, plus_str, sizeof(plus_str), '+'))
 359      -                        goto free_arg_name;
 360      -                if (star)
 361      -                        snprintf(offset_str, sizeof(offset_str), "*(%s%s)", minus_str, plus_str);
 362      -                else
 363      -                        snprintf(offset_str, sizeof(offset_str), "%s%s", minus_str, plus_str);
 364      -                sql_insert_caller_info(call, CONTAINER, param, offset_str, "$(-1)");
 365      -free_arg_name:
 366      -                free_string(arg_name);
 367      -        } END_FOR_EACH_PTR(arg);
 368  420  
 369      -        free_string(fn_name);
      421 +                sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
      422 +        } END_FOR_EACH_PTR(arg);
 370  423  }
 371  424  
 372  425  static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
 373  426  {
 374      -        sval_t offset = {
 375      -                .type = &int_ctype,
 376      -        };
 377      -        const char *arg_offset;
 378      -        int star = 0;
 379      -        int val;
 380      -
 381      -        if (key[0] == '*') {
 382      -                star = 1;
 383      -                key += 2;
 384      -        }
 385      -
 386      -        val = atoi(key);
 387      -        if (val < -4095 || val > 0)
 388      -                return;
 389      -        offset.value = -val;
 390      -        arg_offset = strchr(key, '+');
 391      -        if (!arg_offset)
 392      -                return;
 393      -        val = atoi(arg_offset + 1);
 394      -        if (val > 4095 || val < 0)
 395      -                return;
 396      -        offset.value |= val << 16;
 397      -        if (star)
 398      -                offset.value |= 1ULL << 31;
 399      -
 400      -        set_state(param_id, name, sym, alloc_estate_sval(offset));
      427 +        set_state(param_id, name, sym, alloc_state_str(key));
 401  428  }
 402  429  
 403  430  struct db_info {
 404  431          struct symbol *arg;
 405  432          int prev_offset;
 406  433          struct range_list *rl;
 407  434          int star;
 408  435          struct stree *stree;
 409  436  };
 410  437  
↓ open down ↓ 156 lines elided ↑ open up ↑
 567  594          if (!star && !arg_offset) {
 568  595                  sval_t sval;
 569  596  
 570  597                  sval.type = get_real_base_type(arg);
 571  598                  sval.uvalue = tag;
 572  599                  set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval));
 573  600          }
 574  601          return db_info.stree;
 575  602  }
 576  603  
 577      -static void handle_passed_container(struct symbol *sym)
      604 +static void load_container_data(struct symbol *arg, const char *info)
 578  605  {
 579      -        struct symbol *arg;
 580      -        struct smatch_state *state;
      606 +        mtag_t cur_tag, container_tag, arg_tag;
      607 +        int container_offset, arg_offset;
      608 +        char *p = (char *)info;
 581  609          struct sm_state *sm;
 582  610          struct stree *stree;
 583      -        mtag_t fn_tag, container_tag, arg_tag;
 584      -        sval_t offset;
 585      -        int container_offset, arg_offset;
 586      -        int star;
      611 +        bool star = 0;
 587  612  
 588      -        FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
 589      -                state = get_state(param_id, arg->ident->name, arg);
 590      -                if (state)
 591      -                        goto found;
 592      -        } END_FOR_EACH_PTR(arg);
      613 +        if (p[0] == '*') {
      614 +                star = 1;
      615 +                p += 2;
      616 +        }
 593  617  
 594      -        return;
 595      -found:
 596      -        if (!estate_get_single_value(state, &offset))
      618 +        if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
 597  619                  return;
 598      -        container_offset = -(offset.value & 0xffff);
 599      -        arg_offset = (offset.value & 0xfff0000) >> 16;
 600      -        star = !!(offset.value & (1ULL << 31));
 601  620  
 602      -        if (!get_toplevel_mtag(cur_func_sym, &fn_tag))
      621 +        while (true) {
      622 +                container_offset = strtoul(p, &p, 0);
      623 +                if (local_debug)
      624 +                        sm_msg("%s: cur_tag = %llu container_offset = %d",
      625 +                               __func__, cur_tag, container_offset);
      626 +                if (!mtag_map_select_container(cur_tag, container_offset, &container_tag))
      627 +                        return;
      628 +                cur_tag = container_tag;
      629 +                if (local_debug)
      630 +                        sm_msg("%s: container_tag = %llu p = '%s'",
      631 +                               __func__, container_tag, p);
      632 +                if (!p)
      633 +                        return;
      634 +                if (p[0] != '-')
      635 +                        break;
      636 +                p++;
      637 +        }
      638 +
      639 +        if (p[0] != '+')
 603  640                  return;
 604      -        if (!mtag_map_select_container(fn_tag, container_offset, &container_tag))
      641 +
      642 +        p++;
      643 +        arg_offset = strtoul(p, &p, 0);
      644 +        if (p && *p && *p != ')')
 605  645                  return;
      646 +
 606  647          if (!arg_offset || star) {
 607  648                  arg_tag = container_tag;
 608  649          } else {
 609  650                  if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag))
 610  651                          return;
 611  652          }
 612  653  
 613  654          stree = load_tag_info_sym(arg_tag, arg, arg_offset, star);
 614  655          FOR_EACH_SM(stree, sm) {
 615  656                  set_state(sm->owner, sm->name, sm->sym, sm->state);
 616  657          } END_FOR_EACH_SM(sm);
 617  658          free_stree(&stree);
 618  659  }
 619  660  
      661 +static void handle_passed_container(struct symbol *sym)
      662 +{
      663 +        struct symbol *arg;
      664 +        struct smatch_state *state;
      665 +
      666 +        FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
      667 +                state = get_state(param_id, arg->ident->name, arg);
      668 +                if (!state || state == &merged)
      669 +                        continue;
      670 +                load_container_data(arg, state->name);
      671 +        } END_FOR_EACH_PTR(arg);
      672 +}
      673 +
 620  674  void register_container_of(int id)
 621  675  {
 622  676          my_id = id;
 623  677  
 624  678          add_hook(&match_function_def, FUNC_DEF_HOOK);
 625  679  
 626  680          add_get_state_hook(&get_state_hook);
 627  681  
 628  682          add_hook(&match_save_states, INLINE_FN_START);
 629  683          add_hook(&match_restore_states, INLINE_FN_END);
 630  684  
 631  685          select_return_implies_hook(CONTAINER, &set_param_used);
 632  686          all_return_states_hook(&process_states);
 633  687  
 634  688          add_split_return_callback(&print_returns_container_of);
 635  689          select_return_states_hook(CONTAINER, &returns_container_of);
 636  690  
 637  691          add_hook(&match_call, FUNCTION_CALL_HOOK);
 638  692  }
 639  693  
 640      -static struct smatch_state *unmatched_state(struct sm_state *sm)
 641      -{
 642      -        return alloc_estate_whole(estate_type(sm->state));
 643      -}
 644      -
 645  694  void register_container_of2(int id)
 646  695  {
 647  696          param_id = id;
 648  697  
      698 +        set_dynamic_states(param_id);
 649  699          select_caller_info_hook(db_passed_container, CONTAINER);
      700 +        add_merge_hook(param_id, &merge_str_state);
 650  701          add_hook(&handle_passed_container, AFTER_DEF_HOOK);
 651      -        add_unmatched_state_hook(param_id, &unmatched_state);
 652      -        add_merge_hook(param_id, &merge_estates);
 653  702  }
 654  703  
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX