Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/icontext.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* Context state operations */
18
#include "ghost.h"
19
#include "gsstruct.h"   /* for gxalloc.h */
20
#include "gxalloc.h"
21
#include "ierrors.h"
22
#include "stream.h"   /* for files.h */
23
#include "files.h"
24
#include "idict.h"
25
#include "igstate.h"
26
#include "icontext.h"
27
#include "interp.h"
28
#include "isave.h"
29
#include "dstack.h"
30
#include "estack.h"
31
#include "store.h"
32
33
/* Declare the GC descriptors for embedded objects. */
34
extern_st(st_gs_dual_memory);
35
extern_st(st_ref_stack);
36
extern_st(st_dict_stack);
37
extern_st(st_exec_stack);
38
extern_st(st_op_stack);
39
40
/* GC descriptors */
41
static
42
CLEAR_MARKS_PROC(context_state_clear_marks)
43
333k
{
44
333k
    gs_context_state_t *const pcst = vptr;
45
46
333k
    r_clear_attrs(&pcst->stdio[0], l_mark);
47
333k
    r_clear_attrs(&pcst->stdio[1], l_mark);
48
333k
    r_clear_attrs(&pcst->stdio[2], l_mark);
49
333k
    r_clear_attrs(&pcst->error_object, l_mark);
50
333k
    r_clear_attrs(&pcst->userparams, l_mark);
51
333k
    r_clear_attrs(&pcst->LocalFontDirectory, l_mark);
52
333k
    r_clear_attrs(&pcst->GlobalFontDirectory, l_mark);
53
333k
    r_clear_attrs(&pcst->internaldict, l_mark);
54
333k
    r_clear_attrs(&pcst->op_array_table_global.table, l_mark);
55
333k
    r_clear_attrs(&pcst->op_array_table_local.table, l_mark);
56
333k
}
57
static
58
14.0M
ENUM_PTRS_WITH(context_state_enum_ptrs, gs_context_state_t *pcst) {
59
4.66M
    index -= 14;
60
4.66M
    if (index < st_gs_dual_memory_num_ptrs)
61
0
        return ENUM_USING(st_gs_dual_memory, &pcst->memory,
62
4.66M
                          sizeof(pcst->memory), index);
63
4.66M
    index -= st_gs_dual_memory_num_ptrs;
64
4.66M
    if (index < st_dict_stack_num_ptrs)
65
1.33M
        return ENUM_USING(st_dict_stack, &pcst->dict_stack,
66
4.66M
                          sizeof(pcst->dict_stack), index);
67
3.33M
    index -= st_dict_stack_num_ptrs;
68
3.33M
    if (index < st_exec_stack_num_ptrs)
69
1.33M
        return ENUM_USING(st_exec_stack, &pcst->exec_stack,
70
3.33M
                          sizeof(pcst->exec_stack), index);
71
2.00M
    index -= st_exec_stack_num_ptrs;
72
2.00M
    return ENUM_USING(st_op_stack, &pcst->op_stack,
73
3.33M
                      sizeof(pcst->op_stack), index);
74
3.33M
    }
75
3.33M
    ENUM_PTR(0, gs_context_state_t, pgs);
76
667k
    case 1: ENUM_RETURN_REF(&pcst->stdio[0]);
77
667k
    case 2: ENUM_RETURN_REF(&pcst->stdio[1]);
78
667k
    case 3: ENUM_RETURN_REF(&pcst->stdio[2]);
79
667k
    case 4: ENUM_RETURN_REF(&pcst->error_object);
80
3.33M
    ENUM_PTR(5, gs_context_state_t, invalid_file_stream);
81
667k
    case 6: ENUM_RETURN_REF(&pcst->userparams);
82
667k
    case 7: ENUM_RETURN_REF(&pcst->internaldict);
83
667k
    case 8: ENUM_RETURN_REF(&pcst->LocalFontDirectory);
84
667k
    case 9: ENUM_RETURN_REF(&pcst->GlobalFontDirectory);
85
3.33M
    ENUM_PTR(10, gs_context_state_t, op_array_table_global.nx_table);
86
3.33M
    ENUM_PTR(11, gs_context_state_t, op_array_table_local.nx_table);
87
667k
    case 12: ENUM_RETURN_REF(&pcst->op_array_table_global.table);
88
667k
    case 13: ENUM_RETURN_REF(&pcst->op_array_table_local.table);
89
14.0M
ENUM_PTRS_END
90
333k
static RELOC_PTRS_WITH(context_state_reloc_ptrs, gs_context_state_t *pcst);
91
333k
    RELOC_PTR(gs_context_state_t, pgs);
92
333k
    RELOC_USING(st_gs_dual_memory, &pcst->memory, sizeof(pcst->memory));
93
    /******* WHY DON'T WE CLEAR THE l_mark OF stdio? ******/
94
333k
    RELOC_REF_VAR(pcst->stdio[0]);
95
333k
    RELOC_REF_VAR(pcst->stdio[1]);
96
333k
    RELOC_REF_VAR(pcst->stdio[2]);
97
333k
    RELOC_PTR(gs_context_state_t, invalid_file_stream);
98
333k
    RELOC_REF_VAR(pcst->error_object);
99
333k
    r_clear_attrs(&pcst->error_object, l_mark);
100
333k
    RELOC_REF_VAR(pcst->userparams);
101
333k
    r_clear_attrs(&pcst->userparams, l_mark);
102
333k
    RELOC_REF_VAR(pcst->internaldict);
103
333k
    r_clear_attrs(&pcst->internaldict, l_mark);
104
105
333k
    RELOC_REF_VAR(pcst->LocalFontDirectory);
106
333k
    r_clear_attrs(&pcst->LocalFontDirectory, l_mark);
107
333k
    RELOC_REF_VAR(pcst->GlobalFontDirectory);
108
333k
    r_clear_attrs(&pcst->GlobalFontDirectory, l_mark);
109
110
333k
    RELOC_PTR(gs_context_state_t, op_array_table_global.nx_table);
111
333k
    RELOC_PTR(gs_context_state_t, op_array_table_local.nx_table);
112
333k
    RELOC_REF_VAR(pcst->op_array_table_global.table);
113
333k
    r_clear_attrs(&pcst->op_array_table_global.table, l_mark);
114
333k
    RELOC_REF_VAR(pcst->op_array_table_local.table);
115
333k
    r_clear_attrs(&pcst->op_array_table_local.table, l_mark);
116
333k
    RELOC_USING(st_dict_stack, &pcst->dict_stack, sizeof(pcst->dict_stack));
117
333k
    RELOC_USING(st_exec_stack, &pcst->exec_stack, sizeof(pcst->exec_stack));
118
333k
    RELOC_USING(st_op_stack, &pcst->op_stack, sizeof(pcst->op_stack));
119
333k
RELOC_PTRS_END
120
public_st_context_state();
121
122
/* Allocate the state of a context. */
123
int
124
context_state_alloc(gs_context_state_t ** ppcst,
125
                    const ref *psystem_dict,
126
                    const gs_dual_memory_t * dmem)
127
162k
{
128
162k
    gs_ref_memory_t *mem = dmem->space_local;
129
162k
    gs_context_state_t *pcst = *ppcst;
130
162k
    int code;
131
162k
    int i;
132
133
162k
    if (pcst == 0) {
134
162k
        pcst = gs_alloc_struct((gs_memory_t *) mem, gs_context_state_t,
135
162k
                               &st_context_state, "context_state_alloc");
136
162k
        if (pcst == 0)
137
0
            return_error(gs_error_VMerror);
138
162k
    }
139
    /* Make sure pcst->memory is valid, in case we return an error. */
140
162k
    pcst->memory = *dmem;
141
162k
    code = gs_interp_alloc_stacks(mem, pcst);
142
162k
    if (code < 0)
143
0
        goto x0;
144
    /*
145
     * We have to initialize the dictionary stack early,
146
     * for far-off references to systemdict.
147
     */
148
162k
    pcst->dict_stack.system_dict = *psystem_dict;
149
162k
    pcst->dict_stack.min_size = 0;
150
162k
    pcst->dict_stack.userdict_index = 0;
151
162k
    pcst->pgs = int_gstate_alloc(dmem);
152
162k
    if (pcst->pgs == 0) {
153
0
        code = gs_note_error(gs_error_VMerror);
154
0
        goto x1;
155
0
    }
156
162k
    pcst->language_level = 1;
157
162k
    make_false(&pcst->array_packing);
158
162k
    make_int(&pcst->binary_object_format, 0);
159
162k
    pcst->nv_page_count = 0;
160
162k
    pcst->rand_state = rand_state_initial;
161
162k
    pcst->usertime_inited = false;
162
162k
    pcst->plugin_list = 0;
163
162k
    make_t(&pcst->error_object, t__invalid);
164
165
    /* The following get set properly in obj_init(), but
166
       init them so the garbager doesn't barf in the event
167
       of a error during initialisation
168
     */
169
162k
    make_t(&pcst->LocalFontDirectory, t__invalid);
170
162k
    make_t(&pcst->GlobalFontDirectory, t__invalid);
171
172
162k
    { /*
173
         * Create an empty userparams dictionary of the right size.
174
         * If we can't determine the size, pick an arbitrary one.
175
         */
176
162k
        ref *puserparams;
177
162k
        uint size;
178
162k
        ref *system_dict = &pcst->dict_stack.system_dict;
179
180
162k
        if (dict_find_string(system_dict, "userparams", &puserparams) > 0)
181
0
            size = dict_length(puserparams);
182
162k
        else
183
162k
            size = 300;
184
162k
        code = dict_alloc(pcst->memory.space_local, size, &pcst->userparams);
185
162k
        if (code < 0)
186
0
            goto x2;
187
        /* PostScript code initializes the user parameters. */
188
162k
    }
189
162k
    { /*
190
         * Create an empty internaldict dictionary.
191
         */
192
162k
        code = dict_alloc(pcst->memory.space_local, 13, &pcst->internaldict);
193
162k
        if (code < 0)
194
0
            goto x2;
195
        /* PostScript code initializes the user parameters. */
196
162k
    }
197
162k
    pcst->scanner_options = 0;
198
162k
    pcst->LockFilePermissions = false;
199
162k
    pcst->starting_arg_file = false;
200
162k
    pcst->RenderTTNotdef = true;
201
202
162k
    pcst->invalid_file_stream = (stream*)gs_alloc_struct_immovable(mem->stable_memory,
203
162k
                                          stream, &st_stream,
204
162k
                                          "context_state_alloc");
205
162k
    if (pcst->invalid_file_stream == NULL) {
206
0
        code = gs_note_error(gs_error_VMerror);
207
0
        goto x3;
208
0
    }
209
210
162k
    s_init(pcst->invalid_file_stream, mem->stable_memory);
211
162k
    sread_string(pcst->invalid_file_stream, NULL, 0);
212
162k
    s_init_no_id(pcst->invalid_file_stream);
213
214
    /* The initial stdio values are bogus.... */
215
162k
    make_file(&pcst->stdio[0], a_readonly | avm_invalid_file_entry, 1,
216
162k
              pcst->invalid_file_stream);
217
162k
    make_file(&pcst->stdio[1], a_all | avm_invalid_file_entry, 1,
218
162k
              pcst->invalid_file_stream);
219
162k
    make_file(&pcst->stdio[2], a_all | avm_invalid_file_entry, 1,
220
162k
              pcst->invalid_file_stream);
221
811k
    for (i = countof(pcst->memory.spaces_indexed); --i >= 0;)
222
648k
        if (dmem->spaces_indexed[i] != 0)
223
486k
            ++(dmem->spaces_indexed[i]->num_contexts);
224
    /* The number of interpreter "ticks" between calls on the time_slice_proc.
225
     * Currently, the clock ticks before each operator, and at each
226
     * procedure return. */
227
162k
    pcst->time_slice_ticks = 0x7fff;
228
162k
    *ppcst = pcst;
229
230
162k
    pcst->system_params.CurDisplayList = 0;
231
162k
    pcst->system_params.CurFormCache = 0;
232
162k
    pcst->system_params.CurOutlineCache = 0;
233
162k
    pcst->system_params.CurPatternCache = 0;
234
162k
    pcst->system_params.CurScreenStorage = 0;
235
162k
    pcst->system_params.CurSourceList = 0;
236
162k
    pcst->system_params.CurStoredScreenCache = 0;
237
162k
    pcst->system_params.CurUPathCache = 0;
238
162k
    pcst->system_params.MaxDisplayAndSourceList = 140000;
239
162k
    pcst->system_params.MaxDisplayList = 140000;
240
162k
    pcst->system_params.MaxFormCache = 100000;
241
162k
    pcst->system_params.MaxImageBuffer = 524288;
242
162k
    pcst->system_params.MaxOutlineCache = 65000;
243
162k
    pcst->system_params.MaxPatternCache = 100000;
244
162k
    pcst->system_params.MaxUPathCache = 300000;
245
162k
    pcst->system_params.MaxScreenStorage = 84000;
246
162k
    pcst->system_params.MaxSourceList = 25000;
247
162k
    pcst->system_params.RamSize = 4194304;
248
162k
    pcst->system_params.JobTimeout = 0;
249
162k
    pcst->system_params.WaitTimeout = 40;
250
162k
    pcst->system_params.GenericResourceDir = NULL;
251
162k
    pcst->system_params.FontResourceDir = NULL;
252
162k
    pcst->system_params.GenericResourcePathSep = NULL;
253
162k
    pcst->system_params.PercentDiskFontResourceDir = NULL;
254
162k
    pcst->system_params.PercentDiskGenericResourceDir = NULL;
255
162k
    pcst->system_params.SystemParamsPassword = NULL;
256
162k
    pcst->system_params.StartJobPassword = NULL;
257
258
162k
    pcst->user_params.MaxFormItem = 100000;
259
162k
    pcst->user_params.MaxPatternItem = 20000;
260
162k
    pcst->user_params.MaxScreenItem = 48000;
261
162k
    pcst->user_params.MaxUPathItem = 0;
262
162k
    pcst->user_params.MaxSuperScreen = 1016;
263
162k
    pcst->user_params.JobName = NULL;
264
162k
    pcst->user_params.IdiomRecognition = false;
265
162k
    pcst->user_params.HalftoneMode = 0;
266
267
162k
    return 0;
268
0
  x3:/* No need to delete dictionary here, as gc will do it for us. */
269
0
  x2:gs_gstate_free(pcst->pgs);
270
0
  x1:gs_interp_free_stacks(mem, pcst);
271
0
  x0:if (*ppcst == 0)
272
0
        gs_free_object((gs_memory_t *) mem, pcst, "context_state_alloc");
273
0
    return code;
274
0
}
275
276
/* Load the interpreter state from a context. */
277
int
278
context_state_load(gs_context_state_t * i_ctx_p)
279
495k
{
280
495k
    gs_ref_memory_t *lmem = iimemory_local;
281
495k
    ref *system_dict = systemdict;
282
495k
    uint space = r_space(system_dict);
283
495k
    dict_stack_t *dstack = &idict_stack;
284
495k
    int code;
285
286
    /*
287
     * Disable save checking, and space check for systemdict, while
288
     * copying dictionaries.
289
     */
290
495k
    alloc_set_not_in_save(idmemory);
291
495k
    r_set_space(system_dict, avm_max);
292
    /*
293
     * Set systemdict.userparams to the saved copy, and then
294
     * set the actual user parameters.  Note that we must disable both
295
     * space checking and save checking while doing this.  Also,
296
     * we must do this after copying localdicts (if required), because
297
     * userparams also appears in localdicts.
298
     */
299
495k
    code = dict_put_string(system_dict, "userparams", &i_ctx_p->userparams,
300
495k
                           dstack);
301
495k
    if (code >= 0)
302
495k
        code = set_user_params(i_ctx_p, &i_ctx_p->userparams);
303
495k
    r_set_space(system_dict, space);
304
495k
    if (lmem->save_level > 0)
305
171k
        alloc_set_in_save(idmemory);
306
495k
    estack_clear_cache(&iexec_stack);
307
495k
    dstack_set_top(&idict_stack);
308
495k
    return code;
309
495k
}
310
311
/* Store the interpreter state in a context. */
312
int
313
context_state_store(gs_context_state_t * pcst)
314
333k
{
315
333k
    ref_stack_cleanup(&pcst->dict_stack.stack);
316
333k
    ref_stack_cleanup(&pcst->exec_stack.stack);
317
333k
    ref_stack_cleanup(&pcst->op_stack.stack);
318
    /*
319
     * The user parameters in systemdict.userparams are kept
320
     * up to date by PostScript code, but we still need to save
321
     * systemdict.userparams to get the correct l_new flag.
322
     */
323
333k
    {
324
333k
        ref *puserparams;
325
        /* We need i_ctx_p for access to the d_stack. */
326
333k
        i_ctx_t *i_ctx_p = pcst;
327
328
333k
        if (dict_find_string(systemdict, "userparams", &puserparams) <= 0)
329
0
            return_error(gs_error_Fatal);
330
333k
        pcst->userparams = *puserparams;
331
333k
    }
332
0
    return 0;
333
333k
}
334
335
/* Free the contents of the state of a context, always to its local VM. */
336
/* Return a mask of which of its VMs, if any, we freed. */
337
int
338
context_state_free(gs_context_state_t * pcst)
339
0
{
340
0
    gs_ref_memory_t *mem = pcst->memory.space_local;
341
0
    int freed = 0;
342
0
    int i;
343
344
    /*
345
     * If this context is the last one referencing a particular VM
346
     * (local / global / system), free the entire VM space;
347
     * otherwise, just free the context-related structures.
348
     */
349
0
    for (i = countof(pcst->memory.spaces_indexed); --i >= 0;) {
350
0
        if (pcst->memory.spaces_indexed[i] != 0 &&
351
0
            !--(pcst->memory.spaces_indexed[i]->num_contexts)
352
0
            ) {
353
/****** FREE THE ENTIRE SPACE ******/
354
0
            freed |= 1 << i;
355
0
        }
356
0
    }
357
    /*
358
     * If we freed any spaces at all, we must have freed the local
359
     * VM where the context structure and its substructures were
360
     * allocated.
361
     */
362
0
    if (freed)
363
0
        return freed;
364
0
    {
365
0
        gs_gstate *pgs = pcst->pgs;
366
367
0
        gs_grestoreall(pgs);
368
        /* Patch the saved pointer so we can do the last grestore. */
369
0
        {
370
0
            gs_gstate *saved = gs_gstate_saved(pgs);
371
372
0
            gs_gstate_swap_saved(saved, saved);
373
0
        }
374
0
        gs_grestore(pgs);
375
0
        gs_gstate_swap_saved(pgs, (gs_gstate *) 0);
376
0
        gs_gstate_free(pgs);
377
0
    }
378
/****** FREE USERPARAMS ******/
379
0
    gs_interp_free_stacks(mem, pcst);
380
0
    return 0;
381
0
}