Coverage Report

Created: 2025-06-24 07:01

/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 */