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 /*
15  * These are checking routines calls to which could be inserted by a
16  * preprocessor to validate C pointer arithmetic.
17  */
18 
19 #include "private/gc_pmark.h"
20 
21 #ifdef __STDC__
GC_default_same_obj_print_proc(GC_PTR p,GC_PTR q)22 void GC_default_same_obj_print_proc(GC_PTR p, GC_PTR q)
23 #else
24 void GC_default_same_obj_print_proc (p, q)
25 GC_PTR p, q;
26 #endif
27 {
28     GC_err_printf2("0x%lx and 0x%lx are not in the same object\n",
29     		   (unsigned long)p, (unsigned long)q);
30     ABORT("GC_same_obj test failed");
31 }
32 
33 void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
34 		= GC_default_same_obj_print_proc;
35 
36 /* Check that p and q point to the same object.  Call		*/
37 /* *GC_same_obj_print_proc if they don't.			*/
38 /* Returns the first argument.  (Return value may be hard 	*/
39 /* to use,due to typing issues.  But if we had a suitable 	*/
40 /* preprocessor ...)						*/
41 /* Succeeds if neither p nor q points to the heap.		*/
42 /* We assume this is performance critical.  (It shouldn't	*/
43 /* be called by production code, but this can easily make	*/
44 /* debugging intolerably slow.)					*/
45 #ifdef __STDC__
GC_same_obj(register void * p,register void * q)46   GC_PTR GC_same_obj(register void *p, register void *q)
47 #else
48   GC_PTR GC_same_obj(p, q)
49   register char *p, *q;
50 #endif
51 {
52     register struct hblk *h;
53     register hdr *hhdr;
54     register ptr_t base, limit;
55     register word sz;
56 
57     if (!GC_is_initialized) GC_init();
58     hhdr = HDR((word)p);
59     if (hhdr == 0) {
60    	if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
61    	    && HDR((word)q) != 0) {
62    	    goto fail;
63    	}
64    	return(p);
65     }
66     /* If it's a pointer to the middle of a large object, move it	*/
67     /* to the beginning.						*/
68     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
69     	h = HBLKPTR(p) - (word)hhdr;
70     	hhdr = HDR(h);
71 	while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
72 	   h = FORWARDED_ADDR(h, hhdr);
73 	   hhdr = HDR(h);
74 	}
75 	limit = (ptr_t)((word *)h + hhdr -> hb_sz);
76 	if ((ptr_t)p >= limit || (ptr_t)q >= limit || (ptr_t)q < (ptr_t)h ) {
77 	    goto fail;
78 	}
79 	return(p);
80     }
81     sz = WORDS_TO_BYTES(hhdr -> hb_sz);
82     if (sz > MAXOBJBYTES) {
83       base = (ptr_t)HBLKPTR(p);
84       limit = base + sz;
85       if ((ptr_t)p >= limit) {
86         goto fail;
87       }
88     } else {
89       register int map_entry;
90       register int pdispl = HBLKDISPL(p);
91 
92       map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
93       if (map_entry > CPP_MAX_OFFSET) {
94          map_entry = BYTES_TO_WORDS(pdispl) % BYTES_TO_WORDS(sz);
95 	 if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
96 	 	/* W/o this check, we might miss an error if 	*/
97 	 	/* q points to the first object on a page, and	*/
98 	 	/* points just before the page.			*/
99       }
100       base = (char *)((word)p & ~(WORDS_TO_BYTES(1) - 1));
101       base -= WORDS_TO_BYTES(map_entry);
102       limit = base + sz;
103     }
104     /* [base, limit) delimits the object containing p, if any.	*/
105     /* If p is not inside a valid object, then either q is	*/
106     /* also outside any valid object, or it is outside 		*/
107     /* [base, limit).						*/
108     if ((ptr_t)q >= limit || (ptr_t)q < base) {
109     	goto fail;
110     }
111     return(p);
112 fail:
113     (*GC_same_obj_print_proc)((ptr_t)p, (ptr_t)q);
114     return(p);
115 }
116 
117 #ifdef __STDC__
GC_default_is_valid_displacement_print_proc(GC_PTR p)118 void GC_default_is_valid_displacement_print_proc (GC_PTR p)
119 #else
120 void GC_default_is_valid_displacement_print_proc (p)
121 GC_PTR p;
122 #endif
123 {
124     GC_err_printf1("0x%lx does not point to valid object displacement\n",
125     		   (unsigned long)p);
126     ABORT("GC_is_valid_displacement test failed");
127 }
128 
129 void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
130 	GC_default_is_valid_displacement_print_proc;
131 
132 /* Check that if p is a pointer to a heap page, then it points to	*/
133 /* a valid displacement within a heap object.				*/
134 /* Uninteresting with GC_all_interior_pointers.				*/
135 /* Always returns its argument.						*/
136 /* Note that we don't lock, since nothing relevant about the header	*/
137 /* should change while we have a valid object pointer to the block.	*/
138 #ifdef __STDC__
GC_is_valid_displacement(void * p)139   void * GC_is_valid_displacement(void *p)
140 #else
141   char *GC_is_valid_displacement(p)
142   char *p;
143 #endif
144 {
145     register hdr *hhdr;
146     register word pdispl;
147     register struct hblk *h;
148     register map_entry_type map_entry;
149     register word sz;
150 
151     if (!GC_is_initialized) GC_init();
152     hhdr = HDR((word)p);
153     if (hhdr == 0) return(p);
154     h = HBLKPTR(p);
155     if (GC_all_interior_pointers) {
156 	while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
157 	   h = FORWARDED_ADDR(h, hhdr);
158 	   hhdr = HDR(h);
159 	}
160     }
161     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
162     	goto fail;
163     }
164     sz = WORDS_TO_BYTES(hhdr -> hb_sz);
165     pdispl = HBLKDISPL(p);
166     map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
167     if (map_entry == OBJ_INVALID
168     	|| sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
169     	goto fail;
170     }
171     return(p);
172 fail:
173     (*GC_is_valid_displacement_print_proc)((ptr_t)p);
174     return(p);
175 }
176 
177 #ifdef __STDC__
GC_default_is_visible_print_proc(GC_PTR p)178 void GC_default_is_visible_print_proc(GC_PTR p)
179 #else
180 void GC_default_is_visible_print_proc(p)
181 GC_PTR p;
182 #endif
183 {
184     GC_err_printf1("0x%lx is not a GC visible pointer location\n",
185     		   (unsigned long)p);
186     ABORT("GC_is_visible test failed");
187 }
188 
189 void (*GC_is_visible_print_proc) GC_PROTO((GC_PTR p)) =
190 	GC_default_is_visible_print_proc;
191 
192 /* Could p be a stack address? */
GC_on_stack(p)193 GC_bool GC_on_stack(p)
194 ptr_t p;
195 {
196 #   ifdef THREADS
197 	return(TRUE);
198 #   else
199 	int dummy;
200 #   	ifdef STACK_GROWS_DOWN
201 	    if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
202 	    	return(TRUE);
203 	    }
204 #	else
205 	    if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
206 	    	return(TRUE);
207 	    }
208 #	endif
209 	return(FALSE);
210 #   endif
211 }
212 
213 /* Check that p is visible						*/
214 /* to the collector as a possibly pointer containing location.		*/
215 /* If it isn't invoke *GC_is_visible_print_proc.			*/
216 /* Returns the argument in all cases.  May erroneously succeed		*/
217 /* in hard cases.  (This is intended for debugging use with		*/
218 /* untyped allocations.  The idea is that it should be possible, though	*/
219 /* slow, to add such a call to all indirect pointer stores.)		*/
220 /* Currently useless for multithreaded worlds.				*/
221 #ifdef __STDC__
GC_is_visible(void * p)222   void * GC_is_visible(void *p)
223 #else
224   char *GC_is_visible(p)
225   char *p;
226 #endif
227 {
228     register hdr *hhdr;
229 
230     if ((word)p & (ALIGNMENT - 1)) goto fail;
231     if (!GC_is_initialized) GC_init();
232 #   ifdef THREADS
233 	hhdr = HDR((word)p);
234         if (hhdr != 0 && GC_base(p) == 0) {
235             goto fail;
236         } else {
237             /* May be inside thread stack.  We can't do much. */
238             return(p);
239         }
240 #   else
241 	/* Check stack first: */
242 	  if (GC_on_stack(p)) return(p);
243 	hhdr = HDR((word)p);
244     	if (hhdr == 0) {
245     	    GC_bool result;
246 
247     	    if (GC_is_static_root(p)) return(p);
248     	    /* Else do it again correctly:	*/
249 #           if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || \
250 		defined(MSWINCE) || defined(PCR)) \
251                 && !defined(SRC_M3)
252     	        DISABLE_SIGNALS();
253     	        GC_register_dynamic_libraries();
254     	        result = GC_is_static_root(p);
255     	        ENABLE_SIGNALS();
256     	        if (result) return(p);
257 #	    endif
258     	    goto fail;
259     	} else {
260     	    /* p points to the heap. */
261     	    word descr;
262     	    ptr_t base = GC_base(p);	/* Should be manually inlined? */
263 
264     	    if (base == 0) goto fail;
265     	    if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
266     	    descr = hhdr -> hb_descr;
267     retry:
268     	    switch(descr & GC_DS_TAGS) {
269     	        case GC_DS_LENGTH:
270     	            if ((word)((ptr_t)p - (ptr_t)base) > (word)descr) goto fail;
271     	            break;
272     	        case GC_DS_BITMAP:
273     	            if ((ptr_t)p - (ptr_t)base
274     	                 >= WORDS_TO_BYTES(BITMAP_BITS)
275     	                 || ((word)p & (sizeof(word) - 1))) goto fail;
276     	            if (!((1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
277     	            	  & descr)) goto fail;
278     	            break;
279     	        case GC_DS_PROC:
280     	            /* We could try to decipher this partially. 	*/
281     	            /* For now we just punt.				*/
282     	            break;
283     	        case GC_DS_PER_OBJECT:
284 		    if ((signed_word)descr >= 0) {
285     	              descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
286 		    } else {
287 		      ptr_t type_descr = *(ptr_t *)base;
288 		      descr = *(word *)(type_descr
289 			      - (descr - (GC_DS_PER_OBJECT
290 					  - GC_INDIR_PER_OBJ_BIAS)));
291 		    }
292     	            goto retry;
293     	    }
294     	    return(p);
295     	}
296 #   endif
297 fail:
298     (*GC_is_visible_print_proc)((ptr_t)p);
299     return(p);
300 }
301 
302 
GC_pre_incr(p,how_much)303 GC_PTR GC_pre_incr (p, how_much)
304 GC_PTR *p;
305 size_t how_much;
306 {
307     GC_PTR initial = *p;
308     GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
309 
310     if (!GC_all_interior_pointers) {
311     	(void) GC_is_valid_displacement(result);
312     }
313     return (*p = result);
314 }
315 
GC_post_incr(p,how_much)316 GC_PTR GC_post_incr (p, how_much)
317 GC_PTR *p;
318 size_t how_much;
319 {
320     GC_PTR initial = *p;
321     GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
322 
323     if (!GC_all_interior_pointers) {
324     	(void) GC_is_valid_displacement(result);
325     }
326     *p = result;
327     return(initial);
328 }
329