OSDN Git Service

* ltconfig (osf[345]): Append $major to soname_spec.
[pf3gnuchains/gcc-fork.git] / boehm-gc / ptr_chck.c
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__
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__
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 > WORDS_TO_BYTES(MAXOBJSZ)) {
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__
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__
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 > MAXOBJSZ && (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__
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? */
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__
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
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
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 }