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