/src/ghostpdl/psi/ilocate.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Object locating and validating for Ghostscript memory manager */ |
18 | | #include "ghost.h" |
19 | | #include "memory_.h" |
20 | | #include "ierrors.h" |
21 | | #include "gsexit.h" |
22 | | #include "gsstruct.h" |
23 | | #include "iastate.h" |
24 | | #include "idict.h" |
25 | | #include "igc.h" /* for gc_state_t and gcst_get_memory_ptr() */ |
26 | | #include "igcstr.h" /* for prototype */ |
27 | | #include "iname.h" |
28 | | #include "ipacked.h" |
29 | | #include "isstate.h" |
30 | | #include "iutil.h" /* for packed_get */ |
31 | | #include "ivmspace.h" |
32 | | #include "store.h" |
33 | | |
34 | | #ifdef DEBUG |
35 | | static int do_validate_clump(const clump_t * cp, gc_state_t * gcst); |
36 | | static int do_validate_object(const obj_header_t * ptr, const clump_t * cp, |
37 | | gc_state_t * gcst); |
38 | | #endif |
39 | | |
40 | | |
41 | | /* ================ Locating ================ */ |
42 | | |
43 | | /* Locate a pointer in the clumps of a space being collected. */ |
44 | | /* This is only used for string garbage collection and for debugging. */ |
45 | | clump_t * |
46 | | gc_locate(const void *ptr, gc_state_t * gcst) |
47 | 4.92G | { |
48 | 4.92G | gs_ref_memory_t *mem; |
49 | 4.92G | gs_ref_memory_t *other; |
50 | | |
51 | 4.92G | if (clump_locate(ptr, &gcst->loc)) |
52 | 4.91G | return gcst->loc.cp; |
53 | 8.72M | mem = gcst->loc.memory; |
54 | | |
55 | | /* |
56 | | * Try the stable allocator of this space, or, if the current memory |
57 | | * is the stable one, the non-stable allocator of this space. |
58 | | */ |
59 | | |
60 | 8.72M | if ((other = (gs_ref_memory_t *)mem->stable_memory) != mem || |
61 | 8.72M | (other = gcst->spaces_indexed[mem->space >> r_space_shift]) != mem |
62 | 8.72M | ) { |
63 | 5.76M | gcst->loc.memory = other; |
64 | 5.76M | gcst->loc.cp = 0; |
65 | 5.76M | if (clump_locate(ptr, &gcst->loc)) |
66 | 1.38M | return gcst->loc.cp; |
67 | 5.76M | } |
68 | | |
69 | | /* |
70 | | * Try the other space, if there is one, including its stable allocator |
71 | | * and all save levels. (If the original space is system space, try |
72 | | * local space.) |
73 | | */ |
74 | | |
75 | 7.33M | if (gcst->space_local != gcst->space_global) { |
76 | 7.33M | gcst->loc.memory = other = |
77 | 7.33M | (mem->space == avm_local ? gcst->space_global : gcst->space_local); |
78 | 7.33M | gcst->loc.cp = 0; |
79 | 7.33M | if (clump_locate(ptr, &gcst->loc)) |
80 | 30.5k | return gcst->loc.cp; |
81 | | /* Try its stable allocator. */ |
82 | 7.30M | if (other->stable_memory != (const gs_memory_t *)other) { |
83 | 7.30M | gcst->loc.memory = (gs_ref_memory_t *)other->stable_memory; |
84 | 7.30M | gcst->loc.cp = 0; |
85 | 7.30M | if (clump_locate(ptr, &gcst->loc)) |
86 | 33.2k | return gcst->loc.cp; |
87 | 7.27M | gcst->loc.memory = other; |
88 | 7.27M | } |
89 | | /* Try other save levels of this space. */ |
90 | 49.0M | while (gcst->loc.memory->saved != 0) { |
91 | 42.3M | gcst->loc.memory = &gcst->loc.memory->saved->state; |
92 | 42.3M | gcst->loc.cp = 0; |
93 | 42.3M | if (clump_locate(ptr, &gcst->loc)) |
94 | 632k | return gcst->loc.cp; |
95 | 42.3M | } |
96 | 7.27M | } |
97 | | |
98 | | /* |
99 | | * Try system space. This is simpler because it isn't subject to |
100 | | * save/restore and doesn't have a separate stable allocator. |
101 | | */ |
102 | | |
103 | 6.64M | if (mem != gcst->space_system) { |
104 | 3.68M | gcst->loc.memory = gcst->space_system; |
105 | 3.68M | gcst->loc.cp = 0; |
106 | 3.68M | if (clump_locate(ptr, &gcst->loc)) |
107 | 2.95M | return gcst->loc.cp; |
108 | 3.68M | } |
109 | | |
110 | | /* |
111 | | * Try other save levels of the initial space, or of global space if the |
112 | | * original space was system space. In the latter case, try all |
113 | | * levels, and its stable allocator. |
114 | | */ |
115 | | |
116 | 3.68M | switch (mem->space) { |
117 | 2.95M | default: /* system */ |
118 | 2.95M | other = gcst->space_global; |
119 | 2.95M | if (other->stable_memory != (const gs_memory_t *)other) { |
120 | 2.95M | gcst->loc.memory = (gs_ref_memory_t *)other->stable_memory; |
121 | 2.95M | gcst->loc.cp = 0; |
122 | 2.95M | if (clump_locate(ptr, &gcst->loc)) |
123 | 34.7k | return gcst->loc.cp; |
124 | 2.95M | } |
125 | 2.92M | gcst->loc.memory = other; |
126 | 2.92M | break; |
127 | 693k | case avm_global: |
128 | 693k | gcst->loc.memory = gcst->space_global; |
129 | 693k | break; |
130 | 31.8k | case avm_local: |
131 | 31.8k | gcst->loc.memory = gcst->space_local; |
132 | 31.8k | break; |
133 | 3.68M | } |
134 | 19.6M | for (;;) { |
135 | 19.6M | if (gcst->loc.memory != mem) { /* don't do twice */ |
136 | 19.4M | gcst->loc.cp = 0; |
137 | 19.4M | if (clump_locate(ptr, &gcst->loc)) |
138 | 3.48M | return gcst->loc.cp; |
139 | 19.4M | } |
140 | 16.1M | if (gcst->loc.memory->saved == 0) |
141 | 159k | break; |
142 | 16.0M | gcst->loc.memory = &gcst->loc.memory->saved->state; |
143 | 16.0M | } |
144 | | |
145 | | /* Restore locator to a legal state and report failure. */ |
146 | | |
147 | 159k | gcst->loc.memory = mem; |
148 | 159k | gcst->loc.cp = 0; |
149 | 159k | return 0; |
150 | 3.64M | } |
151 | | |
152 | | /* ================ Debugging ================ */ |
153 | | |
154 | | #ifdef DEBUG |
155 | | |
156 | | /* Define the structure for temporarily saving allocator state. */ |
157 | | typedef struct alloc_temp_save_s { |
158 | | clump_t *cc; |
159 | | obj_size_t rsize; |
160 | | ref rlast; |
161 | | } alloc_temp_save_t; |
162 | | /* Temporarily save the state of an allocator. */ |
163 | | static void |
164 | | alloc_temp_save(alloc_temp_save_t *pats, gs_ref_memory_t *mem) |
165 | | { |
166 | | obj_header_t *rcur; |
167 | | |
168 | | pats->cc = mem->cc; |
169 | | if (mem->cc == NULL) |
170 | | return; |
171 | | rcur = mem->cc->rcur; |
172 | | if (rcur != 0) { |
173 | | pats->rsize = rcur[-1].o_size; |
174 | | rcur[-1].o_size = mem->cc->rtop - (byte *) rcur; |
175 | | /* Create the final ref, reserved for the GC. */ |
176 | | pats->rlast = ((ref *) mem->cc->rtop)[-1]; |
177 | | make_mark((ref *) mem->cc->rtop - 1); |
178 | | } |
179 | | } |
180 | | /* Restore the temporarily saved state. */ |
181 | | static void |
182 | | alloc_temp_restore(alloc_temp_save_t *pats, gs_ref_memory_t *mem) |
183 | | { |
184 | | obj_header_t *rcur; |
185 | | |
186 | | if (mem->cc && (rcur = mem->cc->rcur) != NULL) { |
187 | | rcur[-1].o_size = pats->rsize; |
188 | | ((ref *) mem->cc->rtop)[-1] = pats->rlast; |
189 | | } |
190 | | mem->cc = pats->cc; |
191 | | } |
192 | | |
193 | | /* Validate the contents of an allocator. */ |
194 | | void |
195 | | ialloc_validate_spaces(const gs_dual_memory_t * dmem) |
196 | | { |
197 | | int i; |
198 | | gc_state_t state; |
199 | | alloc_temp_save_t |
200 | | save[countof(dmem->spaces_indexed)], |
201 | | save_stable[countof(dmem->spaces_indexed)]; |
202 | | gs_ref_memory_t *mem; |
203 | | |
204 | | state.spaces = dmem->spaces; |
205 | | state.loc.memory = state.space_local; |
206 | | state.loc.cp = 0; |
207 | | state.heap = dmem->current->non_gc_memory; /* valid 'heap' needed for printing */ |
208 | | |
209 | | /* Save everything we need to reset temporarily. */ |
210 | | |
211 | | for (i = 0; i < countof(save); i++) |
212 | | if ((mem = dmem->spaces_indexed[i]) != 0) { |
213 | | alloc_temp_save(&save[i], mem); |
214 | | if (mem->stable_memory != (gs_memory_t *)mem) |
215 | | alloc_temp_save(&save_stable[i], |
216 | | (gs_ref_memory_t *)mem->stable_memory); |
217 | | } |
218 | | |
219 | | /* Validate memory. */ |
220 | | |
221 | | for (i = 0; i < countof(save); i++) |
222 | | if ((mem = dmem->spaces_indexed[i]) != 0) { |
223 | | ialloc_validate_memory(mem, &state); |
224 | | if (mem->stable_memory != (gs_memory_t *)mem) |
225 | | ialloc_validate_memory((gs_ref_memory_t *)mem->stable_memory, |
226 | | &state); |
227 | | } |
228 | | |
229 | | /* Undo temporary changes. */ |
230 | | |
231 | | for (i = 0; i < countof(save); i++) |
232 | | if ((mem = dmem->spaces_indexed[i]) != 0) { |
233 | | if (mem->stable_memory != (gs_memory_t *)mem) |
234 | | alloc_temp_restore(&save_stable[i], |
235 | | (gs_ref_memory_t *)mem->stable_memory); |
236 | | alloc_temp_restore(&save[i], mem); |
237 | | } |
238 | | } |
239 | | void |
240 | | ialloc_validate_memory(const gs_ref_memory_t * mem, gc_state_t * gcst) |
241 | | { |
242 | | const gs_ref_memory_t *smem; |
243 | | int level; |
244 | | |
245 | | for (smem = mem, level = 0; smem != 0; |
246 | | smem = &smem->saved->state, --level |
247 | | ) { |
248 | | clump_splay_walker sw; |
249 | | const clump_t *cp; |
250 | | int i; |
251 | | |
252 | | if_debug3m('6', (gs_memory_t *)mem, "[6]validating memory "PRI_INTPTR", space %d, level %d\n", |
253 | | (intptr_t) mem, mem->space, level); |
254 | | /* Validate clumps. */ |
255 | | for (cp = clump_splay_walk_init(&sw, smem); cp != 0; cp = clump_splay_walk_fwd(&sw)) |
256 | | if (do_validate_clump(cp, gcst)) { |
257 | | mlprintf3((gs_memory_t *)mem, "while validating memory "PRI_INTPTR", space %d, level %d\n", |
258 | | (intptr_t) mem, mem->space, level); |
259 | | gs_abort(gcst->heap); |
260 | | } |
261 | | /* Validate freelists. */ |
262 | | for (i = 0; i < num_freelists; ++i) { |
263 | | uint free_size = i << log2_obj_align_mod; |
264 | | const obj_header_t *pfree; |
265 | | |
266 | | for (pfree = mem->freelists[i]; pfree != 0; |
267 | | pfree = *(const obj_header_t * const *)pfree |
268 | | ) { |
269 | | obj_size_t size = pfree[-1].o_size; |
270 | | |
271 | | if (pfree[-1].o_type != &st_free) { |
272 | | mlprintf3((gs_memory_t *)mem, "Non-free object "PRI_INTPTR"(%u) on freelist %i!\n", |
273 | | (intptr_t) pfree, size, i); |
274 | | break; |
275 | | } |
276 | | if ((i == LARGE_FREELIST_INDEX && size < max_freelist_size) || |
277 | | (i != LARGE_FREELIST_INDEX && |
278 | | (size < free_size - obj_align_mask || size > free_size))) { |
279 | | mlprintf3((gs_memory_t *)mem, "Object "PRI_INTPTR"(%u) size wrong on freelist %i!\n", |
280 | | (intptr_t) pfree, (uint)size, i); |
281 | | break; |
282 | | } |
283 | | if (pfree == *(const obj_header_t* const*)pfree) |
284 | | break; |
285 | | } |
286 | | } |
287 | | }; |
288 | | } |
289 | | |
290 | | /* Check the validity of an object's size. */ |
291 | | static inline bool |
292 | | object_size_valid(const obj_header_t * pre, uint size, const clump_t * cp) |
293 | | { |
294 | | return (pre->o_alone ? (const byte *)pre == cp->cbase : |
295 | | size <= cp->ctop - (const byte *)(pre + 1)); |
296 | | } |
297 | | |
298 | | /* Validate all the objects in a clump. */ |
299 | | #if IGC_PTR_STABILITY_CHECK |
300 | | void ialloc_validate_pointer_stability(const obj_header_t * ptr_from, |
301 | | const obj_header_t * ptr_to); |
302 | | static int ialloc_validate_ref(const ref *, gc_state_t *, const obj_header_t *pre_fr); |
303 | | static int ialloc_validate_ref_packed(const ref_packed *, gc_state_t *, const obj_header_t *pre_fr); |
304 | | #else |
305 | | static int ialloc_validate_ref(const ref *, gc_state_t *); |
306 | | static int ialloc_validate_ref_packed(const ref_packed *, gc_state_t *); |
307 | | #endif |
308 | | static int |
309 | | do_validate_clump(const clump_t * cp, gc_state_t * gcst) |
310 | | { |
311 | | int ret = 0; |
312 | | |
313 | | if_debug_clump('6', gcst->heap, "[6]validating clump", cp); |
314 | | SCAN_CLUMP_OBJECTS(cp); |
315 | | DO_ALL |
316 | | if (pre->o_type == &st_free) { |
317 | | if (!object_size_valid(pre, size, cp)) { |
318 | | lprintf3("Bad free object "PRI_INTPTR"(%lu), in clump "PRI_INTPTR"!\n", |
319 | | (intptr_t) (pre + 1), (ulong) size, (intptr_t) cp); |
320 | | return 1; |
321 | | } |
322 | | } else if (do_validate_object(pre + 1, cp, gcst)) { |
323 | | dmprintf_clump(gcst->heap, "while validating clump", cp); |
324 | | return 1; |
325 | | } |
326 | | if_debug3m('7', gcst->heap, " [7]validating %s(%lu) "PRI_INTPTR"\n", |
327 | | struct_type_name_string(pre->o_type), |
328 | | (ulong) size, (intptr_t) pre); |
329 | | if (pre->o_type == &st_refs) { |
330 | | const ref_packed *rp = (const ref_packed *)(pre + 1); |
331 | | const char *end = (const char *)rp + size; |
332 | | |
333 | | while ((const char *)rp < end) { |
334 | | # if IGC_PTR_STABILITY_CHECK |
335 | | ret = ialloc_validate_ref_packed(rp, gcst, pre); |
336 | | # else |
337 | | ret = ialloc_validate_ref_packed(rp, gcst); |
338 | | # endif |
339 | | if (ret) { |
340 | | mlprintf3(gcst->heap, "while validating %s(%lu) "PRI_INTPTR"\n", |
341 | | struct_type_name_string(pre->o_type), |
342 | | (ulong) size, (intptr_t) pre); |
343 | | dmprintf_clump(gcst->heap, "in clump", cp); |
344 | | return ret; |
345 | | } |
346 | | rp = packed_next(rp); |
347 | | } |
348 | | } else { |
349 | | struct_proc_enum_ptrs((*proc)) = pre->o_type->enum_ptrs; |
350 | | uint index = 0; |
351 | | enum_ptr_t eptr; |
352 | | gs_ptr_type_t ptype; |
353 | | |
354 | | if (proc != gs_no_struct_enum_ptrs) |
355 | | for (; (ptype = (*proc) (gcst_get_memory_ptr(gcst), |
356 | | pre + 1, size, index, &eptr, |
357 | | pre->o_type, gcst)) != 0; ++index) { |
358 | | if (eptr.ptr == 0) |
359 | | DO_NOTHING; |
360 | | /* NB check other types ptr_string_type, etc. */ |
361 | | else if (ptype == ptr_struct_type) { |
362 | | ret = do_validate_object(eptr.ptr, NULL, gcst); |
363 | | # if IGC_PTR_STABILITY_CHECK |
364 | | ialloc_validate_pointer_stability(pre, |
365 | | (const obj_header_t *)eptr.ptr - 1); |
366 | | # endif |
367 | | } else if (ptype == ptr_ref_type) |
368 | | # if IGC_PTR_STABILITY_CHECK |
369 | | ret = ialloc_validate_ref_packed(eptr.ptr, gcst, pre); |
370 | | # else |
371 | | ret = ialloc_validate_ref_packed(eptr.ptr, gcst); |
372 | | # endif |
373 | | if (ret) { |
374 | | dmprintf_clump(gcst->heap, "while validating clump", cp); |
375 | | return ret; |
376 | | } |
377 | | } |
378 | | } |
379 | | END_OBJECTS_SCAN |
380 | | return ret; |
381 | | } |
382 | | |
383 | | void |
384 | | ialloc_validate_clump(const clump_t * cp, gc_state_t * gcst) |
385 | | { |
386 | | if (do_validate_clump(cp, gcst)) |
387 | | gs_abort(gcst->heap); |
388 | | } |
389 | | |
390 | | /* Validate a ref. */ |
391 | | #if IGC_PTR_STABILITY_CHECK |
392 | | static int |
393 | | ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst, const obj_header_t *pre_fr) |
394 | | { |
395 | | const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory; |
396 | | |
397 | | if (r_is_packed(rp)) { |
398 | | ref unpacked; |
399 | | |
400 | | packed_get(cmem, rp, &unpacked); |
401 | | return ialloc_validate_ref(&unpacked, gcst, pre_fr); |
402 | | } else { |
403 | | return ialloc_validate_ref((const ref *)rp, gcst, pre_fr); |
404 | | } |
405 | | } |
406 | | #else |
407 | | static int |
408 | | ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst) |
409 | | { |
410 | | const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory; |
411 | | |
412 | | if (r_is_packed(rp)) { |
413 | | ref unpacked; |
414 | | |
415 | | packed_get(cmem, rp, &unpacked); |
416 | | return ialloc_validate_ref(&unpacked, gcst); |
417 | | } else { |
418 | | return ialloc_validate_ref((const ref *)rp, gcst); |
419 | | } |
420 | | } |
421 | | #endif |
422 | | static int |
423 | | ialloc_validate_ref(const ref * pref, gc_state_t * gcst |
424 | | # if IGC_PTR_STABILITY_CHECK |
425 | | , const obj_header_t *pre_fr |
426 | | # endif |
427 | | ) |
428 | | { |
429 | | const void *optr; |
430 | | const ref *rptr; |
431 | | const char *tname; |
432 | | uint size; |
433 | | const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory; |
434 | | int ret = 0; |
435 | | |
436 | | if (!gs_debug_c('?')) |
437 | | return 0; /* no check */ |
438 | | if (r_space(pref) == avm_foreign) |
439 | | return 0; |
440 | | switch (r_type(pref)) { |
441 | | case t_file: |
442 | | optr = pref->value.pfile; |
443 | | goto cks; |
444 | | case t_device: |
445 | | optr = pref->value.pdevice; |
446 | | goto cks; |
447 | | case t_fontID: |
448 | | case t_struct: |
449 | | case t_astruct: |
450 | | optr = pref->value.pstruct; |
451 | | cks: if (optr != 0) { |
452 | | ret = do_validate_object(optr, NULL, gcst); |
453 | | # if IGC_PTR_STABILITY_CHECK |
454 | | ialloc_validate_pointer_stability(pre_fr, |
455 | | (const obj_header_t *)optr - 1); |
456 | | # endif |
457 | | if (ret) { |
458 | | lprintf1("while validating 0x%"PRIx64" (fontID/struct/astruct)\n", |
459 | | (uint64_t)pref); |
460 | | return ret; |
461 | | } |
462 | | } |
463 | | break; |
464 | | case t_name: |
465 | | if (name_index_ptr(cmem, name_index(cmem, pref)) != pref->value.pname) { |
466 | | lprintf3("At "PRI_INTPTR", bad name %u, pname = "PRI_INTPTR"\n", |
467 | | (intptr_t) pref, (uint)name_index(cmem, pref), |
468 | | (intptr_t) pref->value.pname); |
469 | | ret = 1; |
470 | | break; |
471 | | } { |
472 | | ref sref; |
473 | | |
474 | | name_string_ref(cmem, pref, &sref); |
475 | | if (r_space(&sref) != avm_foreign && |
476 | | !gc_locate(sref.value.const_bytes, gcst) |
477 | | ) { |
478 | | lprintf4("At "PRI_INTPTR", bad name %u, pname = "PRI_INTPTR", string "PRI_INTPTR" not in any clump\n", |
479 | | (intptr_t) pref, (uint) r_size(pref), |
480 | | (intptr_t) pref->value.pname, |
481 | | (intptr_t) sref.value.const_bytes); |
482 | | ret = 1; |
483 | | } |
484 | | } |
485 | | break; |
486 | | case t_string: |
487 | | if (r_size(pref) != 0 && !gc_locate(pref->value.bytes, gcst)) { |
488 | | lprintf3("At "PRI_INTPTR", string ptr "PRI_INTPTR"[%u] not in any clump\n", |
489 | | (intptr_t) pref, (intptr_t) pref->value.bytes, |
490 | | (uint) r_size(pref)); |
491 | | ret = 1; |
492 | | } |
493 | | break; |
494 | | case t_array: |
495 | | if (r_size(pref) == 0) |
496 | | break; |
497 | | rptr = pref->value.refs; |
498 | | size = r_size(pref); |
499 | | tname = "array"; |
500 | | cka: if (!gc_locate(rptr, gcst)) { |
501 | | lprintf3("At "PRI_INTPTR", %s "PRI_INTPTR" not in any clump\n", |
502 | | (intptr_t) pref, tname, (intptr_t) rptr); |
503 | | ret = 1; |
504 | | break; |
505 | | } { |
506 | | uint i; |
507 | | |
508 | | for (i = 0; i < size; ++i) { |
509 | | const ref *elt = rptr + i; |
510 | | |
511 | | if (r_is_packed(elt)) { |
512 | | lprintf5("At "PRI_INTPTR", %s "PRI_INTPTR"[%u] element %u is not a ref\n", |
513 | | (intptr_t) pref, tname, (intptr_t) rptr, size, i); |
514 | | ret = 1; |
515 | | } |
516 | | } |
517 | | } |
518 | | break; |
519 | | case t_shortarray: |
520 | | case t_mixedarray: |
521 | | if (r_size(pref) == 0) |
522 | | break; |
523 | | optr = pref->value.packed; |
524 | | if (!gc_locate(optr, gcst)) { |
525 | | lprintf2("At "PRI_INTPTR", packed array "PRI_INTPTR" not in any clump\n", |
526 | | (intptr_t) pref, (intptr_t) optr); |
527 | | ret = 1; |
528 | | } |
529 | | break; |
530 | | case t_dictionary: |
531 | | { |
532 | | const dict *pdict = pref->value.pdict; |
533 | | |
534 | | if (!r_has_type(&pdict->values, t_array) || |
535 | | !r_is_array(&pdict->keys) || |
536 | | !r_has_type(&pdict->count, t_integer) || |
537 | | !r_has_type(&pdict->maxlength, t_integer) |
538 | | ) { |
539 | | lprintf2("At "PRI_INTPTR", invalid dict "PRI_INTPTR"\n", |
540 | | (intptr_t) pref, (intptr_t) pdict); |
541 | | ret = 1; |
542 | | } |
543 | | rptr = (const ref *)pdict; |
544 | | } |
545 | | size = sizeof(dict) / sizeof(ref); |
546 | | tname = "dict"; |
547 | | goto cka; |
548 | | } |
549 | | return ret; |
550 | | } |
551 | | |
552 | | #if IGC_PTR_STABILITY_CHECK |
553 | | /* Validate an pointer stability. */ |
554 | | void |
555 | | ialloc_validate_pointer_stability(const obj_header_t * ptr_fr, |
556 | | const obj_header_t * ptr_to) |
557 | | { |
558 | | static const char *sn[] = {"undef", "undef", "system", "undef", |
559 | | "global_stable", "global", "local_stable", "local"}; |
560 | | |
561 | | if (ptr_fr->d.o.space_id < ptr_to->d.o.space_id) { |
562 | | const char *sn_fr = (ptr_fr->d.o.space_id < count_of(sn) |
563 | | ? sn[ptr_fr->d.o.space_id] : "unknown"); |
564 | | const char *sn_to = (ptr_to->d.o.space_id < count_of(sn) |
565 | | ? sn[ptr_to->d.o.space_id] : "unknown"); |
566 | | |
567 | | lprintf6("Reference to a less stable object "PRI_INTPTR"<%s> " |
568 | | "in the space \'%s\' from "PRI_INTPTR"<%s> in the space \'%s\' !\n", |
569 | | (intptr_t) ptr_to, ptr_to->d.o.t.type->sname, sn_to, |
570 | | (intptr_t) ptr_fr, ptr_fr->d.o.t.type->sname, sn_fr); |
571 | | } |
572 | | } |
573 | | #endif |
574 | | |
575 | | /* Validate an object. */ |
576 | | static int |
577 | | do_validate_object(const obj_header_t * ptr, const clump_t * cp, |
578 | | gc_state_t * gcst) |
579 | | { |
580 | | const obj_header_t *pre = ptr - 1; |
581 | | ulong size = pre_obj_contents_size(pre); |
582 | | gs_memory_type_ptr_t otype = pre->o_type; |
583 | | const char *oname; |
584 | | |
585 | | if (!gs_debug_c('?')) |
586 | | return 0; /* no check */ |
587 | | if (cp == 0 && gcst != 0) { |
588 | | gc_state_t st; |
589 | | |
590 | | st = *gcst; /* no side effects! */ |
591 | | if (!(cp = gc_locate(pre, &st))) { |
592 | | mlprintf1(gcst->heap, "Object "PRI_INTPTR" not in any clump!\n", |
593 | | (intptr_t) ptr); |
594 | | return 1; /*gs_abort(); */ |
595 | | } |
596 | | } |
597 | | if (otype == &st_free) { |
598 | | mlprintf3(gcst->heap, "Reference to free object "PRI_INTPTR"(%lu), in clump "PRI_INTPTR"!\n", |
599 | | (intptr_t) ptr, (ulong) size, (intptr_t) cp); |
600 | | return 1; |
601 | | } |
602 | | if ((cp != 0 && !object_size_valid(pre, size, cp)) || |
603 | | otype->ssize == 0 || |
604 | | (oname = struct_type_name_string(otype), |
605 | | *oname < 33 || *oname > 126) |
606 | | ) { |
607 | | mlprintf2(gcst->heap, "\n Bad object "PRI_INTPTR"(%lu),\n", |
608 | | (intptr_t) ptr, (ulong) size); |
609 | | dmprintf2(gcst->heap, " ssize = %u, in clump "PRI_INTPTR"!\n", |
610 | | otype->ssize, (intptr_t) cp); |
611 | | return 1; |
612 | | } |
613 | | if (size % otype->ssize != 0) { |
614 | | mlprintf3(gcst->heap, "\n Potentially bad object "PRI_INTPTR"(%lu), in clump "PRI_INTPTR"!\n", |
615 | | (intptr_t) ptr, (ulong) size, (intptr_t) cp); |
616 | | dmprintf3(gcst->heap, " structure name = %s, size = %lu, ssize = %u\n", |
617 | | oname, size, otype->ssize); |
618 | | dmprintf(gcst->heap, " This can happen (and is benign) if a device has been subclassed\n"); |
619 | | } |
620 | | |
621 | | return 0; |
622 | | } |
623 | | |
624 | | void |
625 | | ialloc_validate_object(const obj_header_t * ptr, const clump_t * cp, |
626 | | gc_state_t * gcst) |
627 | | { |
628 | | if (do_validate_object(ptr, cp, gcst)) |
629 | | gs_abort(gcst->heap); |
630 | | } |
631 | | #else /* !DEBUG */ |
632 | | |
633 | | void |
634 | | ialloc_validate_spaces(const gs_dual_memory_t * dmem) |
635 | 0 | { |
636 | 0 | } |
637 | | |
638 | | void |
639 | | ialloc_validate_memory(const gs_ref_memory_t * mem, gc_state_t * gcst) |
640 | 0 | { |
641 | 0 | } |
642 | | |
643 | | void |
644 | | ialloc_validate_clump(const clump_t * cp, gc_state_t * gcst) |
645 | 0 | { |
646 | 0 | } |
647 | | |
648 | | void |
649 | | ialloc_validate_object(const obj_header_t * ptr, const clump_t * cp, |
650 | | gc_state_t * gcst) |
651 | 0 | { |
652 | 0 | } |
653 | | |
654 | | #endif /* (!)DEBUG */ |