ptr_chck.c raw

   1  /*
   2   * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
   3   *
   4   * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   5   * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   6   *
   7   * Permission is hereby granted to use or copy this program
   8   * for any purpose, provided the above notices are retained on all copies.
   9   * Permission to modify the code and to distribute modified code is granted,
  10   * provided the above notices are retained, and a notice that the code was
  11   * modified is included with the above copyright notice.
  12   */
  13  
  14  #include "private/gc_pmark.h"
  15  
  16  /*
  17   * These are checking routines calls to which could be inserted by
  18   * a preprocessor to validate C pointer arithmetic.
  19   */
  20  
  21  STATIC void GC_CALLBACK
  22  GC_default_same_obj_print_proc(void *p, void *q)
  23  {
  24    ABORT_ARG2("GC_same_obj test failed",
  25               ": %p and %p are not in the same object", p, q);
  26  }
  27  
  28  GC_same_obj_print_proc_t GC_same_obj_print_proc
  29      = GC_default_same_obj_print_proc;
  30  
  31  GC_API void *GC_CALL
  32  GC_same_obj(void *p, void *q)
  33  {
  34    hdr *hhdr;
  35    ptr_t base, limit;
  36    size_t sz;
  37  
  38    if (UNLIKELY(!GC_is_initialized))
  39      GC_init();
  40    hhdr = HDR(p);
  41    if (NULL == hhdr) {
  42      if (divHBLKSZ(ADDR(p)) != divHBLKSZ(ADDR(q)) && HDR(q) != NULL) {
  43        GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
  44      }
  45      return p;
  46    }
  47    /*
  48     * If it is a pointer to the middle of a large object, move it to
  49     * the beginning.
  50     */
  51    if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
  52      struct hblk *h = GC_find_starting_hblk(HBLKPTR(p), &hhdr);
  53  
  54      limit = (ptr_t)h + hhdr->hb_sz;
  55      if (ADDR_GE((ptr_t)p, limit) || ADDR_GE((ptr_t)q, limit)
  56          || ADDR_LT((ptr_t)q, (ptr_t)h)) {
  57        GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
  58      }
  59      return p;
  60    }
  61    sz = hhdr->hb_sz;
  62    if (sz > MAXOBJBYTES) {
  63      base = (ptr_t)HBLKPTR(p);
  64      limit = base + sz;
  65      if (ADDR_GE((ptr_t)p, limit)) {
  66        GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
  67        return p;
  68      }
  69    } else {
  70      size_t offset;
  71  
  72      if (HBLKPTR(p) != HBLKPTR(q)) {
  73        /*
  74         * Without this check, we might miss an error if `q` points to
  75         * the first object on a page, and points just before the page.
  76         */
  77        GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
  78        return p;
  79      }
  80      offset = HBLKDISPL(p) % sz;
  81      base = (ptr_t)p - offset;
  82      limit = base + sz;
  83    }
  84    /*
  85     * [`base`,`limit`) delimits the object containing `p`, if any.
  86     * If `p` is not inside a valid object, then either `q` is also
  87     * outside any valid object, or it is outside [`base`,`limit`).
  88     */
  89    if (!ADDR_INSIDE((ptr_t)q, base, limit)) {
  90      GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
  91    }
  92    return p;
  93  }
  94  
  95  STATIC void GC_CALLBACK
  96  GC_default_is_valid_displacement_print_proc(void *p)
  97  {
  98    ABORT_ARG1("GC_is_valid_displacement test failed", ": %p not valid", p);
  99  }
 100  
 101  GC_valid_ptr_print_proc_t GC_is_valid_displacement_print_proc
 102      = GC_default_is_valid_displacement_print_proc;
 103  
 104  GC_API void *GC_CALL
 105  GC_is_valid_displacement(void *p)
 106  {
 107    hdr *hhdr;
 108    size_t offset;
 109    struct hblk *h;
 110    size_t sz;
 111  
 112    if (UNLIKELY(!GC_is_initialized))
 113      GC_init();
 114    if (NULL == p)
 115      return NULL;
 116    hhdr = HDR(p);
 117    if (NULL == hhdr)
 118      return p;
 119    h = HBLKPTR(p);
 120    if (GC_all_interior_pointers) {
 121      h = GC_find_starting_hblk(h, &hhdr);
 122    } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
 123      GC_is_valid_displacement_print_proc((ptr_t)p);
 124      return p;
 125    }
 126    sz = hhdr->hb_sz;
 127    offset = HBLKDISPL(p) % sz;
 128    if ((sz > MAXOBJBYTES && ADDR_GE((ptr_t)p, (ptr_t)h + sz))
 129        || !GC_valid_offsets[offset]
 130        || (ADDR_LT((ptr_t)(h + 1), (ptr_t)p + sz - offset)
 131            && !IS_FORWARDING_ADDR_OR_NIL(HDR(h + 1)))) {
 132      GC_is_valid_displacement_print_proc((ptr_t)p);
 133    }
 134    return p;
 135  }
 136  
 137  STATIC void GC_CALLBACK
 138  GC_default_is_visible_print_proc(void *p)
 139  {
 140    ABORT_ARG1("GC_is_visible test failed", ": %p not GC-visible", p);
 141  }
 142  
 143  GC_valid_ptr_print_proc_t GC_is_visible_print_proc
 144      = GC_default_is_visible_print_proc;
 145  
 146  #ifndef THREADS
 147  /* Could `p` be a stack address? */
 148  STATIC GC_bool
 149  GC_on_stack(ptr_t p)
 150  {
 151    return HOTTER_THAN(p, GC_stackbottom) && !HOTTER_THAN(p, GC_approx_sp());
 152  }
 153  
 154  /* Is the address `p` in one of the registered static root sections? */
 155  STATIC GC_bool
 156  GC_is_static_root(ptr_t p)
 157  {
 158    static size_t last_static_root_set = MAX_ROOT_SETS;
 159    size_t i;
 160  
 161  #  if defined(CPPCHECK)
 162    if (n_root_sets > MAX_ROOT_SETS)
 163      ABORT("Bad n_root_sets");
 164  #  endif
 165    if (last_static_root_set < n_root_sets
 166        && ADDR_INSIDE(p, GC_static_roots[last_static_root_set].r_start,
 167                       GC_static_roots[last_static_root_set].r_end))
 168      return TRUE;
 169    for (i = 0; i < n_root_sets; i++) {
 170      if (ADDR_INSIDE(p, GC_static_roots[i].r_start, GC_static_roots[i].r_end)) {
 171        last_static_root_set = i;
 172        return TRUE;
 173      }
 174    }
 175    return FALSE;
 176  }
 177  #endif /* !THREADS */
 178  
 179  GC_API void *GC_CALL
 180  GC_is_visible(void *p)
 181  {
 182    const hdr *hhdr;
 183  
 184    if ((ADDR(p) & (ALIGNMENT - 1)) != 0)
 185      goto fail;
 186    if (UNLIKELY(!GC_is_initialized))
 187      GC_init();
 188  #ifdef THREADS
 189    hhdr = HDR(p);
 190    if (hhdr != NULL && NULL == GC_base(p)) {
 191      goto fail;
 192    } else {
 193      /* May be inside thread stack.  We cannot do much. */
 194      return p;
 195    }
 196  #else
 197    /* Check stack first. */
 198    if (GC_on_stack((ptr_t)p))
 199      return p;
 200  
 201    hhdr = HDR(p);
 202    if (NULL == hhdr) {
 203      if (GC_is_static_root((ptr_t)p)) {
 204        return p;
 205      }
 206      /* Else do it again correctly. */
 207  #  if defined(ANY_MSWIN) || defined(DYNAMIC_LOADING)
 208      if (!GC_no_dls) {
 209        GC_register_dynamic_libraries();
 210        if (GC_is_static_root((ptr_t)p))
 211          return p;
 212      }
 213  #  endif
 214    } else {
 215      /* `p` points to the heap. */
 216      word descr;
 217      /* TODO: Should `GC_base` be manually inlined? */
 218      ptr_t base = (ptr_t)GC_base(p);
 219  
 220      if (NULL == base)
 221        goto fail;
 222      if (HBLKPTR(base) != HBLKPTR(p))
 223        hhdr = HDR(base);
 224      descr = hhdr->hb_descr;
 225    retry:
 226      switch (descr & GC_DS_TAGS) {
 227      case GC_DS_LENGTH:
 228        if ((word)((ptr_t)p - base) >= descr)
 229          goto fail;
 230        break;
 231      case GC_DS_BITMAP:
 232        if ((ptr_t)p - base >= (ptrdiff_t)PTRS_TO_BYTES(BITMAP_BITS))
 233          goto fail;
 234  #  if ALIGNMENT != CPP_PTRSZ / 8
 235        if ((ADDR(p) & (sizeof(ptr_t) - 1)) != 0)
 236          goto fail;
 237  #  endif
 238        if (!(((word)1 << (CPP_WORDSZ - 1 - (word)((ptr_t)p - base))) & descr))
 239          goto fail;
 240        break;
 241      case GC_DS_PROC:
 242        /* We could try to decipher this partially.  For now we just punt. */
 243        break;
 244      case GC_DS_PER_OBJECT:
 245        if (!(descr & SIGNB)) {
 246          descr = *(word *)((ptr_t)base + (descr & ~(word)GC_DS_TAGS));
 247        } else {
 248          ptr_t type_descr = *(ptr_t *)base;
 249  
 250          if (UNLIKELY(NULL == type_descr)) {
 251            /* See the comment in `GC_mark_from`. */
 252            goto fail;
 253          }
 254          descr = *(word *)(type_descr
 255                            - ((GC_signed_word)descr
 256                               + (GC_INDIR_PER_OBJ_BIAS - GC_DS_PER_OBJECT)));
 257        }
 258        goto retry;
 259      }
 260      return p;
 261    }
 262  #endif
 263  fail:
 264    GC_is_visible_print_proc((ptr_t)p);
 265    return p;
 266  }
 267  
 268  GC_API void *GC_CALL
 269  GC_pre_incr(void **p, ptrdiff_t how_much)
 270  {
 271    void *initial = *p;
 272    void *result = GC_same_obj((ptr_t)initial + how_much, initial);
 273  
 274    if (!GC_all_interior_pointers) {
 275      (void)GC_is_valid_displacement(result);
 276    }
 277    *p = result;
 278    return result; /*< updated pointer */
 279  }
 280  
 281  GC_API void *GC_CALL
 282  GC_post_incr(void **p, ptrdiff_t how_much)
 283  {
 284    void *initial = *p;
 285    void *result = GC_same_obj((ptr_t)initial + how_much, initial);
 286  
 287    if (!GC_all_interior_pointers) {
 288      (void)GC_is_valid_displacement(result);
 289    }
 290    *p = result;
 291    return initial; /*< original `*p` */
 292  }
 293  
 294  GC_API void GC_CALL
 295  GC_set_same_obj_print_proc(GC_same_obj_print_proc_t fn)
 296  {
 297    GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
 298    GC_same_obj_print_proc = fn;
 299  }
 300  
 301  GC_API GC_same_obj_print_proc_t GC_CALL
 302  GC_get_same_obj_print_proc(void)
 303  {
 304    return GC_same_obj_print_proc;
 305  }
 306  
 307  GC_API void GC_CALL
 308  GC_set_is_valid_displacement_print_proc(GC_valid_ptr_print_proc_t fn)
 309  {
 310    GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
 311    GC_is_valid_displacement_print_proc = fn;
 312  }
 313  
 314  GC_API GC_valid_ptr_print_proc_t GC_CALL
 315  GC_get_is_valid_displacement_print_proc(void)
 316  {
 317    return GC_is_valid_displacement_print_proc;
 318  }
 319  
 320  GC_API void GC_CALL
 321  GC_set_is_visible_print_proc(GC_valid_ptr_print_proc_t fn)
 322  {
 323    GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
 324    GC_is_visible_print_proc = fn;
 325  }
 326  
 327  GC_API GC_valid_ptr_print_proc_t GC_CALL
 328  GC_get_is_visible_print_proc(void)
 329  {
 330    return GC_is_visible_print_proc;
 331  }
 332