Coverage Report

Created: 2026-09-14 07:34

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