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