Print this page
11506 smatch resync

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/smatch_address.c
          +++ new/usr/src/tools/smatch/src/smatch_address.c
↓ open down ↓ 54 lines elided ↑ open up ↑
  55   55                  if (strcmp(expr->member->name, tmp->ident->name) == 0) {
  56   56                          if (i == 1)
  57   57                                  return 0;
  58   58                          return 1;
  59   59                  }
  60   60          } END_FOR_EACH_PTR(tmp);
  61   61  
  62   62          return 0;
  63   63  }
  64   64  
       65 +static bool matches_anonymous_union(struct symbol *sym, const char *member_name)
       66 +{
       67 +        struct symbol *type, *tmp;
       68 +
       69 +        if (sym->ident)
       70 +                return false;
       71 +        type = get_real_base_type(sym);
       72 +        if (!type || type->type != SYM_UNION)
       73 +                return false;
       74 +
       75 +        FOR_EACH_PTR(type->symbol_list, tmp) {
       76 +                if (tmp->ident &&
       77 +                    strcmp(member_name, tmp->ident->name) == 0) {
       78 +                        return true;
       79 +                }
       80 +        } END_FOR_EACH_PTR(tmp);
       81 +
       82 +        return false;
       83 +}
       84 +
  65   85  int get_member_offset(struct symbol *type, const char *member_name)
  66   86  {
  67   87          struct symbol *tmp;
  68   88          int offset;
       89 +        int bits;
  69   90  
  70   91          if (!type || type->type != SYM_STRUCT)
  71   92                  return -1;
  72   93  
       94 +        bits = 0;
  73   95          offset = 0;
  74   96          FOR_EACH_PTR(type->symbol_list, tmp) {
       97 +                if (bits_to_bytes(bits + type_bits(tmp)) > tmp->ctype.alignment) {
       98 +                        offset += bits_to_bytes(bits);
       99 +                        bits = 0;
      100 +                }
  75  101                  offset = ALIGN(offset, tmp->ctype.alignment);
  76  102                  if (tmp->ident &&
  77  103                      strcmp(member_name, tmp->ident->name) == 0) {
  78  104                          return offset;
  79  105                  }
  80      -                offset += type_bytes(tmp);
      106 +                if (matches_anonymous_union(tmp, member_name))
      107 +                        return offset;
      108 +                if (!(type_bits(tmp) % 8) && type_bits(tmp) / 8 == type_bytes(tmp))
      109 +                        offset += type_bytes(tmp);
      110 +                else
      111 +                        bits += type_bits(tmp);
  81  112          } END_FOR_EACH_PTR(tmp);
  82  113          return -1;
  83  114  }
  84  115  
  85  116  int get_member_offset_from_deref(struct expression *expr)
  86  117  {
  87  118          struct symbol *type;
  88  119          struct ident *member;
  89  120          int offset;
  90  121  
↓ open down ↓ 1 lines elided ↑ open up ↑
  92  123                  return -1;
  93  124  
  94  125          if (expr->member_offset >= 0)
  95  126                  return expr->member_offset;
  96  127  
  97  128          member = expr->member;
  98  129          if (!member)
  99  130                  return -1;
 100  131  
 101  132          type = get_type(expr->deref);
      133 +        if (type_is_ptr(type))
      134 +                type = get_real_base_type(type);
 102  135          if (!type || type->type != SYM_STRUCT)
 103  136                  return -1;
 104  137  
 105  138          offset = get_member_offset(type, member->name);
 106  139          if (offset >= 0)
 107  140                  expr->member_offset = offset;
 108  141          return offset;
 109  142  }
 110  143  
 111      -static struct range_list *filter_unknown_negatives(struct range_list *rl)
 112      -{
 113      -        struct data_range *first;
 114      -        struct range_list *filter = NULL;
 115      -
 116      -        first = first_ptr_list((struct ptr_list *)rl);
 117      -
 118      -        if (sval_is_min(first->min) &&
 119      -            sval_is_negative(first->max) &&
 120      -            first->max.value == -1) {
 121      -                add_ptr_list(&filter, first);
 122      -                return rl_filter(rl, filter);
 123      -        }
 124      -
 125      -        return rl;
 126      -}
 127      -
 128  144  static void add_offset_to_pointer(struct range_list **rl, int offset)
 129  145  {
 130  146          sval_t min, max, remove, sval;
 131  147          struct range_list *orig = *rl;
 132  148  
 133  149          /*
 134  150           * Ha ha.  Treating zero as a special case means I'm correct at least a
 135  151           * tiny fraction of the time.  Which is better than nothing.
 136  152           *
 137  153           */
 138  154          if (offset == 0)
 139  155                  return;
 140  156  
      157 +        if (is_unknown_ptr(orig))
      158 +                return;
      159 +
 141  160          /*
 142  161           * This function doesn't necessarily work how you might expect...
 143  162           *
 144  163           * Say you have s64min-(-1),1-s64max and you add 8 then I guess what
 145  164           * we want to say is maybe something like 9-s64max.  This shows that the
 146  165           * min it could be is 9 which is potentially useful information.  But
 147  166           * if we start with (-12),5000000-57777777 and we add 8 then we'd want
 148  167           * the result to be (-4),5000008-57777777 but (-4),5000000-57777777 is
 149  168           * also probably acceptable.  If you start with s64min-s64max then the
 150  169           * result should be 8-s64max.
↓ open down ↓ 6 lines elided ↑ open up ↑
 157  176          orig = cast_rl(&ptr_ctype, orig);
 158  177          min = sval_type_min(&ptr_ctype);
 159  178          min.value = offset;
 160  179          max = sval_type_max(&ptr_ctype);
 161  180  
 162  181          if (!orig || is_whole_rl(orig)) {
 163  182                  *rl = alloc_rl(min, max);
 164  183                  return;
 165  184          }
 166  185  
 167      -        orig = filter_unknown_negatives(orig);
 168      -        /*
 169      -         * FIXME:  This is not really accurate but we're a bit screwed anyway
 170      -         * when we start doing pointer math with error pointers so it's probably
 171      -         * not important.
 172      -         *
 173      -         */
 174      -        if (sval_is_negative(rl_min(orig)))
 175      -                return;
 176      -
 177  186          /* no wrap around */
 178  187          max.uvalue = rl_max(orig).uvalue;
 179  188          if (max.uvalue > sval_type_max(&ptr_ctype).uvalue - offset) {
 180  189                  remove = sval_type_max(&ptr_ctype);
 181  190                  remove.uvalue -= offset;
 182  191                  orig = remove_range(orig, remove, max);
 183  192          }
 184  193  
 185  194          sval.type = &int_ctype;
 186  195          sval.value = offset;
 187  196  
 188  197          *rl = rl_binop(orig, '+', alloc_rl(sval, sval));
 189  198  }
 190  199  
 191  200  static struct range_list *where_allocated_rl(struct symbol *sym)
 192  201  {
 193  202          if (!sym)
 194  203                  return NULL;
 195  204  
 196      -        if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)) {
 197      -                if (sym->initializer)
 198      -                        return alloc_rl(data_seg_min, data_seg_max);
 199      -                else
 200      -                        return alloc_rl(bss_seg_min, bss_seg_max);
 201      -        }
 202      -        return alloc_rl(stack_seg_min, stack_seg_max);
      205 +        return alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
 203  206  }
 204  207  
 205  208  int get_address_rl(struct expression *expr, struct range_list **rl)
 206  209  {
      210 +        struct expression *unop;
      211 +
 207  212          expr = strip_expr(expr);
 208  213          if (!expr)
 209  214                  return 0;
 210  215  
 211  216          if (expr->type == EXPR_STRING) {
 212      -                *rl = alloc_rl(text_seg_min, text_seg_max);
      217 +                *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
 213  218                  return 1;
 214  219          }
 215  220  
 216      -        if (expr->type == EXPR_PREOP && expr->op == '&') {
 217      -                struct expression *unop;
      221 +        if (expr->type == EXPR_PREOP && expr->op == '&')
      222 +                expr = strip_expr(expr->unop);
      223 +        else {
      224 +                struct symbol *type;
 218  225  
 219      -                unop = strip_expr(expr->unop);
 220      -                if (unop->type == EXPR_SYMBOL) {
 221      -                        *rl = where_allocated_rl(unop->symbol);
      226 +                type = get_type(expr);
      227 +                if (!type || type->type != SYM_ARRAY)
      228 +                        return 0;
      229 +        }
      230 +
      231 +        if (expr->type == EXPR_SYMBOL) {
      232 +                *rl = where_allocated_rl(expr->symbol);
      233 +                return 1;
      234 +        }
      235 +
      236 +        if (is_array(expr)) {
      237 +                struct expression *array;
      238 +                struct expression *offset_expr;
      239 +                struct range_list *array_rl, *offset_rl, *bytes_rl, *res;
      240 +                struct symbol *type;
      241 +                sval_t bytes;
      242 +
      243 +                array = get_array_base(expr);
      244 +                offset_expr = get_array_offset(expr);
      245 +
      246 +                type = get_type(array);
      247 +                type = get_real_base_type(type);
      248 +                bytes.type = ssize_t_ctype;
      249 +                bytes.uvalue = type_bytes(type);
      250 +                bytes_rl = alloc_rl(bytes, bytes);
      251 +
      252 +                get_absolute_rl(array, &array_rl);
      253 +                get_absolute_rl(offset_expr, &offset_rl);
      254 +
      255 +                if (type_bytes(type)) {
      256 +                        res = rl_binop(offset_rl, '*', bytes_rl);
      257 +                        res = rl_binop(res, '+', array_rl);
      258 +                        *rl = res;
      259 +                        return true;
      260 +                }
      261 +
      262 +                if (implied_not_equal(array, 0) ||
      263 +                    implied_not_equal(offset_expr, 0)) {
      264 +                        *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
 222  265                          return 1;
 223  266                  }
 224  267  
 225      -                if (unop->type == EXPR_DEREF) {
 226      -                        int offset = get_member_offset_from_deref(unop);
      268 +                return 0;
      269 +        }
 227  270  
      271 +        if (expr->type == EXPR_DEREF && expr->member) {
      272 +                struct range_list *unop_rl;
      273 +                int offset;
      274 +
      275 +                offset = get_member_offset_from_deref(expr);
      276 +                unop = strip_expr(expr->unop);
      277 +                if (unop->type == EXPR_PREOP && unop->op == '*')
 228  278                          unop = strip_expr(unop->unop);
 229      -                        if (unop->type == EXPR_SYMBOL) {
 230      -                                *rl = where_allocated_rl(unop->symbol);
 231      -                        } else if (unop->type == EXPR_PREOP && unop->op == '*') {
 232      -                                unop = strip_expr(unop->unop);
 233      -                                get_absolute_rl(unop, rl);
 234      -                        } else {
 235      -                                return 0;
 236      -                        }
 237  279  
      280 +                if (offset >= 0 &&
      281 +                    get_implied_rl(unop, &unop_rl) &&
      282 +                    !is_whole_rl(unop_rl)) {
      283 +                        *rl = unop_rl;
 238  284                          add_offset_to_pointer(rl, offset);
 239  285                          return 1;
 240  286                  }
      287 +
      288 +                if (implied_not_equal(unop, 0) || offset > 0) {
      289 +                        *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
      290 +                        return 1;
      291 +                }
 241  292  
 242  293                  return 0;
 243  294          }
 244  295  
 245  296          if (is_non_null_array(expr)) {
 246  297                  *rl = alloc_rl(array_min_sval, array_max_sval);
 247  298                  return 1;
 248  299          }
 249  300  
 250  301          return 0;
 251  302  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX