Back to index

plt-scheme  4.2.1
ptr_chck.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00003  *
00004  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00005  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00006  *
00007  * Permission is hereby granted to use or copy this program
00008  * for any purpose,  provided the above notices are retained on all copies.
00009  * Permission to modify the code and to distribute modified code is granted,
00010  * provided the above notices are retained, and a notice that the code was
00011  * modified is included with the above copyright notice.
00012  */
00013 
00014 /*
00015  * These are checking routines calls to which could be inserted by a
00016  * preprocessor to validate C pointer arithmetic.
00017  */
00018 
00019 #include "private/gc_pmark.h"
00020 
00021 #ifdef __STDC__
00022 void GC_default_same_obj_print_proc(GC_PTR p, GC_PTR q)
00023 #else
00024 void GC_default_same_obj_print_proc (p, q)
00025 GC_PTR p, q;
00026 #endif
00027 {
00028     GC_err_printf2("0x%lx and 0x%lx are not in the same object\n",
00029                  (unsigned long)p, (unsigned long)q);
00030     ABORT("GC_same_obj test failed");
00031 }
00032 
00033 void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
00034               = GC_default_same_obj_print_proc;
00035 
00036 /* Check that p and q point to the same object.  Call          */
00037 /* *GC_same_obj_print_proc if they don't.               */
00038 /* Returns the first argument.  (Return value may be hard      */
00039 /* to use,due to typing issues.  But if we had a suitable      */
00040 /* preprocessor ...)                                    */
00041 /* Succeeds if neither p nor q points to the heap.             */
00042 /* We assume this is performance critical.  (It shouldn't      */
00043 /* be called by production code, but this can easily make      */
00044 /* debugging intolerably slow.)                                */
00045 #ifdef __STDC__
00046   GC_PTR GC_same_obj(register void *p, register void *q)
00047 #else
00048   GC_PTR GC_same_obj(p, q)
00049   register char *p, *q;
00050 #endif
00051 {
00052     register struct hblk *h;
00053     register hdr *hhdr;
00054     register ptr_t base, limit;
00055     register word sz;
00056     
00057     if (!GC_is_initialized) GC_init();
00058     hhdr = HDR((word)p);
00059     if (hhdr == 0) {
00060        if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
00061            && HDR((word)q) != 0) {
00062            goto fail;
00063        }
00064        return(p);
00065     }
00066     /* If it's a pointer to the middle of a large object, move it     */
00067     /* to the beginning.                                       */
00068     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
00069        h = HBLKPTR(p) - (word)hhdr;
00070        hhdr = HDR(h);
00071        while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
00072           h = FORWARDED_ADDR(h, hhdr);
00073           hhdr = HDR(h);
00074        }
00075        limit = (ptr_t)((word *)h + hhdr -> hb_sz);
00076        if ((ptr_t)p >= limit || (ptr_t)q >= limit || (ptr_t)q < (ptr_t)h ) {
00077            goto fail;
00078        }
00079        return(p);
00080     }
00081     sz = WORDS_TO_BYTES(hhdr -> hb_sz);
00082     if (sz > MAXOBJBYTES) {
00083       base = (ptr_t)HBLKPTR(p);
00084       limit = base + sz;
00085       if ((ptr_t)p >= limit) {
00086         goto fail;
00087       }
00088     } else {
00089       register int map_entry;
00090       register int pdispl = HBLKDISPL(p);
00091       
00092       map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
00093       if (map_entry > CPP_MAX_OFFSET) {
00094          map_entry = BYTES_TO_WORDS(pdispl) % BYTES_TO_WORDS(sz);
00095         if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
00096               /* W/o this check, we might miss an error if     */
00097               /* q points to the first object on a page, and   */
00098               /* points just before the page.                  */
00099       }
00100       base = (char *)((word)p & ~(WORDS_TO_BYTES(1) - 1));
00101       base -= WORDS_TO_BYTES(map_entry);
00102       limit = base + sz;
00103     }
00104     /* [base, limit) delimits the object containing p, if any. */
00105     /* If p is not inside a valid object, then either q is     */
00106     /* also outside any valid object, or it is outside         */
00107     /* [base, limit).                                          */
00108     if ((ptr_t)q >= limit || (ptr_t)q < base) {
00109        goto fail;
00110     }
00111     return(p);
00112 fail:
00113     (*GC_same_obj_print_proc)((ptr_t)p, (ptr_t)q);
00114     return(p);
00115 }
00116 
00117 #ifdef __STDC__
00118 void GC_default_is_valid_displacement_print_proc (GC_PTR p)
00119 #else
00120 void GC_default_is_valid_displacement_print_proc (p)
00121 GC_PTR p;
00122 #endif
00123 {
00124     GC_err_printf1("0x%lx does not point to valid object displacement\n",
00125                  (unsigned long)p);
00126     ABORT("GC_is_valid_displacement test failed");
00127 }
00128 
00129 void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) = 
00130        GC_default_is_valid_displacement_print_proc;
00131 
00132 /* Check that if p is a pointer to a heap page, then it points to     */
00133 /* a valid displacement within a heap object.                         */
00134 /* Uninteresting with GC_all_interior_pointers.                       */
00135 /* Always returns its argument.                                       */
00136 /* Note that we don't lock, since nothing relevant about the header   */
00137 /* should change while we have a valid object pointer to the block.   */
00138 #ifdef __STDC__
00139   void * GC_is_valid_displacement(void *p)
00140 #else
00141   char *GC_is_valid_displacement(p)
00142   char *p;
00143 #endif
00144 {
00145     register hdr *hhdr;
00146     register word pdispl;
00147     register struct hblk *h;
00148     register map_entry_type map_entry;
00149     register word sz;
00150     
00151     if (!GC_is_initialized) GC_init();
00152     hhdr = HDR((word)p);
00153     if (hhdr == 0) return(p);
00154     h = HBLKPTR(p);
00155     if (GC_all_interior_pointers) {
00156        while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
00157           h = FORWARDED_ADDR(h, hhdr);
00158           hhdr = HDR(h);
00159        }
00160     }
00161     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
00162        goto fail;
00163     }
00164     sz = WORDS_TO_BYTES(hhdr -> hb_sz);
00165     pdispl = HBLKDISPL(p);
00166     map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
00167     if (map_entry == OBJ_INVALID
00168        || sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
00169        goto fail;
00170     }
00171     return(p);
00172 fail:
00173     (*GC_is_valid_displacement_print_proc)((ptr_t)p);
00174     return(p);
00175 }
00176 
00177 #ifdef __STDC__
00178 void GC_default_is_visible_print_proc(GC_PTR p)
00179 #else
00180 void GC_default_is_visible_print_proc(p)
00181 GC_PTR p;
00182 #endif
00183 {
00184     GC_err_printf1("0x%lx is not a GC visible pointer location\n",
00185                  (unsigned long)p);
00186     ABORT("GC_is_visible test failed");
00187 }
00188 
00189 void (*GC_is_visible_print_proc) GC_PROTO((GC_PTR p)) = 
00190        GC_default_is_visible_print_proc;
00191 
00192 /* Could p be a stack address? */
00193 GC_bool GC_on_stack(p)
00194 ptr_t p;
00195 {
00196 #   ifdef THREADS
00197        return(TRUE);
00198 #   else
00199        int dummy;
00200 #      ifdef STACK_GROWS_DOWN
00201            if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
00202               return(TRUE);
00203            }
00204 #      else
00205            if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
00206               return(TRUE);
00207            }
00208 #      endif
00209        return(FALSE);
00210 #   endif
00211 }
00212 
00213 /* Check that p is visible                                     */
00214 /* to the collector as a possibly pointer containing location.        */
00215 /* If it isn't invoke *GC_is_visible_print_proc.               */
00216 /* Returns the argument in all cases.  May erroneously succeed        */
00217 /* in hard cases.  (This is intended for debugging use with           */
00218 /* untyped allocations.  The idea is that it should be possible, though      */
00219 /* slow, to add such a call to all indirect pointer stores.)          */
00220 /* Currently useless for multithreaded worlds.                        */
00221 #ifdef __STDC__
00222   void * GC_is_visible(void *p)
00223 #else
00224   char *GC_is_visible(p)
00225   char *p;
00226 #endif
00227 {
00228     register hdr *hhdr;
00229     
00230     if ((word)p & (ALIGNMENT - 1)) goto fail;
00231     if (!GC_is_initialized) GC_init();
00232 #   ifdef THREADS
00233        hhdr = HDR((word)p);
00234         if (hhdr != 0 && GC_base(p) == 0) {
00235             goto fail;
00236         } else {
00237             /* May be inside thread stack.  We can't do much. */
00238             return(p);
00239         }
00240 #   else
00241        /* Check stack first: */
00242          if (GC_on_stack(p)) return(p);
00243        hhdr = HDR((word)p);
00244        if (hhdr == 0) {
00245            GC_bool result;
00246            
00247            if (GC_is_static_root(p)) return(p);
00248            /* Else do it again correctly: */
00249 #           if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || \
00250               defined(MSWINCE) || defined(PCR)) \
00251                 && !defined(SRC_M3)
00252                DISABLE_SIGNALS();
00253                GC_register_dynamic_libraries();
00254                result = GC_is_static_root(p);
00255                ENABLE_SIGNALS();
00256                if (result) return(p);
00257 #          endif
00258            goto fail;
00259        } else {
00260            /* p points to the heap. */
00261            word descr;
00262            ptr_t base = GC_base(p);       /* Should be manually inlined? */
00263            
00264            if (base == 0) goto fail;
00265            if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
00266            descr = hhdr -> hb_descr;
00267     retry:
00268            switch(descr & GC_DS_TAGS) {
00269                case GC_DS_LENGTH:
00270                    if ((word)((ptr_t)p - (ptr_t)base) > (word)descr) goto fail;
00271                    break;
00272                case GC_DS_BITMAP:
00273                    if ((ptr_t)p - (ptr_t)base
00274                         >= WORDS_TO_BYTES(BITMAP_BITS)
00275                         || ((word)p & (sizeof(word) - 1))) goto fail;
00276                    if (!((1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
00277                        & descr)) goto fail;
00278                    break;
00279                case GC_DS_PROC:
00280                    /* We could try to decipher this partially.        */
00281                    /* For now we just punt.                           */
00282                    break;
00283                case GC_DS_PER_OBJECT:
00284                   if ((signed_word)descr >= 0) {
00285                      descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
00286                   } else {
00287                     ptr_t type_descr = *(ptr_t *)base;
00288                     descr = *(word *)(type_descr
00289                            - (descr - (GC_DS_PER_OBJECT
00290                                      - GC_INDIR_PER_OBJ_BIAS)));
00291                   }
00292                    goto retry;
00293            }
00294            return(p);
00295        }
00296 #   endif
00297 fail:
00298     (*GC_is_visible_print_proc)((ptr_t)p);
00299     return(p);
00300 }
00301 
00302 
00303 GC_PTR GC_pre_incr (p, how_much)
00304 GC_PTR *p;
00305 size_t how_much;
00306 {
00307     GC_PTR initial = *p;
00308     GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
00309     
00310     if (!GC_all_interior_pointers) {
00311        (void) GC_is_valid_displacement(result);
00312     }
00313     return (*p = result);
00314 }
00315 
00316 GC_PTR GC_post_incr (p, how_much)
00317 GC_PTR *p;
00318 size_t how_much;
00319 {
00320     GC_PTR initial = *p;
00321     GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
00322  
00323     if (!GC_all_interior_pointers) {
00324        (void) GC_is_valid_displacement(result);
00325     }
00326     *p = result;
00327     return(initial);
00328 }