Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gsmemory.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
/* Generic allocator support */
18
#include "memory_.h"
19
#include "stdint_.h"
20
#include "gdebug.h"
21
#include "gstypes.h"
22
#include "gsmemory.h"
23
#include "gsmdebug.h"
24
#include "gsrefct.h"    /* to check prototype */
25
#include "gsstruct.h"   /* ditto */
26
27
/* Define the fill patterns for unallocated memory. */
28
const byte gs_alloc_fill_alloc = 0xa1;
29
const byte gs_alloc_fill_block = 0xb1;
30
const byte gs_alloc_fill_collected = 0xc1;
31
const byte gs_alloc_fill_deleted = 0xd1;
32
const byte gs_alloc_fill_free = 0xf1;
33
34
/* A 'structure' type descriptor for free blocks. */
35
gs_public_st_simple(st_free, byte, "(free)");
36
37
/* The 'structure' type descriptor for bytes. */
38
gs_public_st_simple(st_bytes, byte, "bytes");
39
40
/* The structure type descriptor for GC roots. */
41
public_st_gc_root_t();
42
43
/* The descriptors for elements and arrays of const strings. */
44
private_st_const_string();
45
public_st_const_string_element();
46
47
/* GC procedures for bytestrings */
48
gs_ptr_type_t
49
enum_bytestring(enum_ptr_t *pep, const gs_bytestring *pbs)
50
0
{
51
0
    return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_STRING(pbs));
52
0
}
53
gs_ptr_type_t
54
enum_const_bytestring(enum_ptr_t *pep, const gs_const_bytestring *pbs)
55
0
{
56
0
    return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_CONST_STRING(pbs));
57
0
}
58
void
59
reloc_bytestring(gs_bytestring *pbs, gc_state_t *gcst)
60
0
{
61
0
    if (pbs->bytes) {
62
0
        byte *bytes = pbs->bytes;
63
0
        long offset = pbs->data - bytes;
64
65
0
        pbs->bytes = bytes = RELOC_OBJ(bytes);
66
0
        pbs->data = bytes + offset;
67
0
    } else
68
0
        RELOC_STRING_VAR(*(gs_string *)pbs);
69
0
}
70
void
71
reloc_const_bytestring(gs_const_bytestring *pbs, gc_state_t *gcst)
72
0
{
73
0
    if (pbs->bytes) {
74
0
        const byte *bytes = pbs->bytes;
75
0
        long offset = pbs->data - bytes;
76
77
0
        pbs->bytes = bytes = RELOC_OBJ(bytes);
78
0
        pbs->data = bytes + offset;
79
0
    } else
80
0
        RELOC_CONST_STRING_VAR(*(gs_const_string *)pbs);
81
0
}
82
83
/* Fill an unoccupied block with a pattern. */
84
/* Note that the block size may be too large for a single memset. */
85
void
86
gs_alloc_memset(void *ptr, int /*byte */ fill, size_t lsize)
87
0
{
88
0
    size_t msize = lsize;
89
0
    char *p = ptr;
90
0
    int isize;
91
92
0
    for (; msize; msize -= isize, p += isize) {
93
0
        isize = min(msize, max_int);
94
0
        memset(p, fill, isize);
95
0
    }
96
0
}
97
98
/*
99
 * Either allocate (if obj == 0) or resize (if obj != 0) a structure array.
100
 * If obj != 0, pstype is used only for checking (in DEBUG configurations).
101
 */
102
void *
103
gs_resize_struct_array(gs_memory_t *mem, void *obj, size_t num_elements,
104
                       gs_memory_type_ptr_t pstype, client_name_t cname)
105
0
{
106
0
    if (obj == 0)
107
0
        return gs_alloc_struct_array(mem, num_elements, void, pstype, cname);
108
#ifdef DEBUG
109
    if (gs_object_type(mem, obj) != pstype) {
110
        lprintf3("resize_struct_array "PRI_INTPTR", type was "PRI_INTPTR", expected "PRI_INTPTR"!\n",
111
                 (intptr_t)obj, (intptr_t)gs_object_type(mem, obj), (intptr_t)pstype);
112
        return 0;
113
    }
114
#endif
115
0
    return gs_resize_object(mem, obj, num_elements, cname);
116
0
}
117
118
/* Allocate a structure using a "raw memory" allocator.
119
 * really just an alias for gs_alloc_struct_immovable
120
 * with the clients false expectation that it is saving memory
121
 */
122
123
void *
124
gs_raw_alloc_struct_immovable(gs_memory_t * rmem,
125
                              gs_memory_type_ptr_t pstype,
126
                              client_name_t cname)
127
250M
{
128
250M
    return gs_alloc_bytes_immovable(rmem, gs_struct_type_size(pstype), cname);
129
250M
}
130
131
/* No-op freeing procedures */
132
void
133
gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname)
134
10.0M
{
135
10.0M
}
136
void
137
gs_ignore_free_string(gs_memory_t * mem, byte * data, size_t nbytes,
138
                      client_name_t cname)
139
0
{
140
0
}
141
142
/* Deconstifying freeing procedures. */
143
/* These procedures rely on a severely deprecated pun. */
144
void
145
gs_free_const_object(gs_memory_t * mem, const void *data, client_name_t cname)
146
1.97M
{
147
1.97M
    union { const void *r; void *w; } u;
148
149
1.97M
    u.r = data;
150
1.97M
    gs_free_object(mem, u.w, cname);
151
1.97M
}
152
void
153
gs_free_const_string(gs_memory_t * mem, const byte * data, size_t nbytes,
154
                     client_name_t cname)
155
18.9M
{
156
18.9M
    union { const byte *r; byte *w; } u;
157
158
18.9M
    u.r = data;
159
18.9M
    gs_free_string(mem, u.w, nbytes, cname);
160
18.9M
}
161
162
/* Free a [const] bytestring. */
163
void
164
gs_free_bytestring(gs_memory_t *mem, gs_bytestring *pbs, client_name_t cname)
165
0
{
166
0
    if (pbs->bytes)
167
0
        gs_free_object(mem, pbs->bytes, cname);
168
0
    else
169
0
        gs_free_string(mem, pbs->data, pbs->size, cname);
170
0
}
171
void
172
gs_free_const_bytestring(gs_memory_t *mem, gs_const_bytestring *pbs,
173
                         client_name_t cname)
174
0
{
175
0
    if (pbs->bytes)
176
0
        gs_free_const_object(mem, pbs->bytes, cname);
177
0
    else
178
0
        gs_free_const_string(mem, pbs->data, pbs->size, cname);
179
0
}
180
181
/* No-op consolidation procedure */
182
void
183
gs_ignore_consolidate_free(gs_memory_t *mem)
184
0
{
185
0
}
186
187
/* No-op pointer enumeration procedure */
188
ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)
189
27.5M
{
190
27.5M
    return 0;
191
27.5M
    ENUM_PTRS_END_PROC
192
27.5M
}
193
194
/* No-op pointer relocation procedure */
195
57.3M
RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)
196
57.3M
{
197
57.3M
}
198
57.3M
RELOC_PTRS_END
199
200
/* Get the size of a structure from the descriptor. */
201
uint
202
gs_struct_type_size(gs_memory_type_ptr_t pstype)
203
260M
{
204
260M
    return pstype->ssize;
205
260M
}
206
207
/* Get the name of a structure from the descriptor. */
208
struct_name_t
209
gs_struct_type_name(gs_memory_type_ptr_t pstype)
210
6.38k
{
211
6.38k
    return pstype->sname;
212
6.38k
}
213
214
/* Register a structure root. */
215
int
216
gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t **root,
217
                        void **pp, client_name_t cname)
218
3.02M
{
219
3.02M
    return gs_register_root(mem, root, ptr_struct_type, pp, cname);
220
3.02M
}
221
222
/* ---------------- Reference counting ---------------- */
223
224
#ifdef DEBUG
225
226
static const char *
227
rc_object_type_name(const void *vp, const rc_header *prc)
228
{
229
    gs_memory_type_ptr_t pstype;
230
231
    if (prc->memory == 0)
232
        return "(unknown)";
233
    pstype = gs_object_type(prc->memory, vp);
234
    if ((uintptr_t)pstype < 10000)
235
        return ("?????");
236
    if (prc->free != rc_free_struct_only) {
237
        /*
238
         * This object might be stack-allocated or have other unusual memory
239
         * management properties.  Make some reasonableness checks.
240
         * ****** THIS IS A HACK. ******
241
         */
242
        long dist;
243
244
        dist = (const char *)&dist - (const char *)vp;
245
        if (dist < 10000 && dist > -10000)
246
            return "(on stack)";
247
        if ((uintptr_t)pstype < 0x10000)
248
            return "(anomalous)";
249
    }
250
    return client_name_string(gs_struct_type_name(pstype));
251
}
252
253
/* Trace reference count operations. */
254
void
255
rc_trace_init_free(const void *vp, const rc_header *prc)
256
{
257
    dmprintf3(prc->memory, "[^]%s "PRI_INTPTR" init = %ld\n",
258
              rc_object_type_name(vp, prc), (intptr_t)vp, (long)prc->ref_count);
259
}
260
void
261
rc_trace_free_struct(const void *vp, const rc_header *prc, client_name_t cname)
262
{
263
    dmprintf3(prc->memory, "[^]%s "PRI_INTPTR" => free (%s)\n",
264
              rc_object_type_name(vp, prc),
265
              (intptr_t)vp, client_name_string(cname));
266
}
267
void
268
rc_trace_increment(const void *vp, const rc_header *prc)
269
{
270
    dmprintf3(prc->memory, "[^]%s "PRI_INTPTR" ++ => %ld\n",
271
              rc_object_type_name(vp, prc),
272
              (intptr_t)vp, (long)prc->ref_count);
273
}
274
void
275
rc_trace_adjust(const void *vp, const rc_header *prc, int delta, const char *cname)
276
{
277
    dmprintf5(prc->memory, "[^]%s "PRI_INTPTR" %+d => %ld (%s)\n",
278
              rc_object_type_name(vp, prc),
279
              (intptr_t)vp, delta, (long)(prc->ref_count + delta), cname);
280
}
281
282
#endif /* DEBUG */
283
284
/* Normal freeing routine for reference-counted structures. */
285
void
286
rc_free_struct_only(gs_memory_t * mem, void *data, client_name_t cname)
287
78.6M
{
288
78.6M
    if (mem != 0)
289
78.3M
        gs_free_object(mem, data, cname);
290
78.6M
}
291
292
/* ---------------- Basic-structure GC procedures ---------------- */
293
294
/* Enumerate pointers */
295
ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)
296
1.22G
{
297
1.22G
    const gc_struct_data_t *psd = pstype->proc_data;
298
299
    /* This check is primarily for misuse of the alloc_struct_array */
300
    /* with number of elements 0 and allocation not passing 'element' */
301
1.22G
    if (size == 0) {
302
#ifdef DEBUG
303
        dmprintf2(mem, "  basic_enum_ptrs: Attempt to enum 0 size structure at "PRI_INTPTR", type: %s\n",
304
                  (intptr_t)vptr, pstype->sname);
305
#endif
306
0
        return 0;
307
0
    }
308
1.22G
    if (index < psd->num_ptrs) {
309
811M
        const gc_ptr_element_t *ppe = &psd->ptrs[index];
310
811M
        EV_CONST char *pptr = (EV_CONST char *)vptr + ppe->offset;
311
312
#ifdef DEBUG
313
        /* some extra checking to make sure we aren't out of bounds */
314
        if (ppe->offset > size - sizeof(void *)) {
315
            dmprintf4(mem, "  basic_enum_ptrs: Attempt to enum ptr with offset=%d beyond size=%d: structure at "PRI_INTPTR", type: %s\n",
316
                      ppe->offset, size, (intptr_t)vptr, pstype->sname);
317
            return 0;
318
        }
319
#endif
320
811M
        switch ((gc_ptr_type_index_t)ppe->type) {
321
808M
            case GC_ELT_OBJ:
322
808M
                return ENUM_OBJ(*(const void *EV_CONST *)pptr);
323
114k
            case GC_ELT_STRING:
324
114k
                return ENUM_STRING((const gs_string *)pptr);
325
3.11M
            case GC_ELT_CONST_STRING:
326
3.11M
                return ENUM_CONST_STRING((const gs_const_string *)pptr);
327
811M
        }
328
811M
    }
329
414M
    if (!psd->super_type)
330
149M
        return 0;
331
264M
    return ENUM_USING(*(psd->super_type),
332
414M
                      (EV_CONST void *)
333
414M
                        ((EV_CONST char *)vptr + psd->super_offset),
334
414M
                      pstype->ssize, index - psd->num_ptrs);
335
414M
}
336
ENUM_PTRS_END_PROC
337
338
/* Relocate pointers */
339
333M
RELOC_PTRS_BEGIN(basic_reloc_ptrs)
340
333M
{
341
333M
    const gc_struct_data_t *psd = pstype->proc_data;
342
333M
    uint i;
343
344
1.14G
    for (i = 0; i < psd->num_ptrs; ++i) {
345
811M
        const gc_ptr_element_t *ppe = &psd->ptrs[i];
346
811M
        char *pptr = (char *)vptr + ppe->offset;
347
348
811M
        switch ((gc_ptr_type_index_t) ppe->type) {
349
808M
            case GC_ELT_OBJ:
350
808M
                RELOC_OBJ_VAR(*(void **)pptr);
351
808M
                break;
352
114k
            case GC_ELT_STRING:
353
114k
                RELOC_STRING_VAR(*(gs_string *)pptr);
354
114k
                break;
355
3.11M
            case GC_ELT_CONST_STRING:
356
3.11M
                RELOC_CONST_STRING_VAR(*(gs_const_string *)pptr);
357
3.11M
                break;
358
811M
        }
359
811M
    }
360
333M
    if (psd->super_type)
361
79.1M
        RELOC_USING(*(psd->super_type),
362
333M
                      (void *)((char *)vptr + psd->super_offset),
363
333M
                      pstype->ssize);
364
333M
} RELOC_PTRS_END