Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zcontrol.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 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
/* Control operators */
18
#include "string_.h"
19
#include "ghost.h"
20
#include "stream.h"
21
#include "oper.h"
22
#include "estack.h"
23
#include "files.h"
24
#include "ipacked.h"
25
#include "iutil.h"
26
#include "store.h"
27
#include "interp.h"
28
29
/* Forward references */
30
static int check_for_exec(const_os_ptr);
31
static int no_cleanup(i_ctx_t *);
32
static uint count_exec_stack(i_ctx_t *, bool);
33
static uint count_to_stopped(i_ctx_t *, long);
34
static int unmatched_exit(os_ptr, op_proc_t);
35
36
/* See the comment in opdef.h for an invariant which allows */
37
/* more efficient implementation of for, loop, and repeat. */
38
39
/* <[test0 body0 ...]> .cond - */
40
static int cond_continue(i_ctx_t *);
41
static int
42
zcond(i_ctx_t *i_ctx_p)
43
0
{
44
0
    os_ptr op = osp;
45
0
    es_ptr ep = esp;
46
47
0
    check_op(1);
48
    /* Push the array on the e-stack and call the continuation. */
49
0
    if (!r_is_array(op))
50
0
        return_op_typecheck(op);
51
0
    check_execute(*op);
52
0
    if ((r_size(op) & 1) != 0)
53
0
        return_error(gs_error_rangecheck);
54
0
    if (r_size(op) == 0)
55
0
        return zpop(i_ctx_p);
56
0
    check_estack(3);
57
0
    esp = ep += 3;
58
0
    ref_assign(ep - 2, op); /* the cond body */
59
0
    make_op_estack(ep - 1, cond_continue);
60
0
    array_get(imemory, op, 0L, ep);
61
0
    esfile_check_cache();
62
0
    pop(1);
63
0
    return o_push_estack;
64
0
}
65
static int
66
cond_continue(i_ctx_t *i_ctx_p)
67
0
{
68
0
    os_ptr op = osp;
69
0
    es_ptr ep = esp;
70
0
    int code;
71
72
0
    check_op(1);
73
    /* The top element of the e-stack is the remaining tail of */
74
    /* the cond body.  The top element of the o-stack should be */
75
    /* the (boolean) result of the test that is the first element */
76
    /* of the tail. */
77
0
    check_type(*op, t_boolean);
78
0
    if (op->value.boolval) { /* true */
79
0
        array_get(imemory, ep, 1L, ep);
80
0
        esfile_check_cache();
81
0
        code = o_pop_estack;
82
0
    } else if (r_size(ep) > 2) { /* false */
83
0
        const ref_packed *elts = ep->value.packed;
84
85
0
        check_estack(2);
86
0
        ep = esp;
87
0
        r_dec_size(ep, 2);
88
0
        elts = packed_next(elts);
89
0
        elts = packed_next(elts);
90
0
        ep->value.packed = elts;
91
0
        array_get(imemory, ep, 0L, ep + 2);
92
0
        make_op_estack(ep + 1, cond_continue);
93
0
        esp = ep + 2;
94
0
        esfile_check_cache();
95
0
        code = o_push_estack;
96
0
    } else {     /* fall off end of cond */
97
0
        esp = ep - 1;
98
0
        code = o_pop_estack;
99
0
    }
100
0
    pop(1);      /* get rid of the boolean */
101
0
    return code;
102
0
}
103
104
/* <obj> exec - */
105
int
106
zexec(i_ctx_t *i_ctx_p)
107
1.85G
{
108
1.85G
    os_ptr op = osp;
109
1.85G
    int code;
110
111
1.85G
    check_op(1);
112
1.85G
    code = check_for_exec(op);
113
1.85G
    if (code < 0) {
114
0
        return code;
115
0
    }
116
1.85G
    if (!r_has_attr(op, a_executable)) {
117
8.70M
        return 0; /* shortcut, literal object just gets pushed back */
118
8.70M
    }
119
1.84G
    check_estack(1);
120
1.84G
    ++esp;
121
1.84G
    ref_assign(esp, op);
122
1.84G
    esfile_check_cache();
123
1.84G
    pop(1);
124
1.84G
    return o_push_estack;
125
1.84G
}
126
127
/* <obj1> ... <objn> <n> .execn - */
128
static int
129
zexecn(i_ctx_t *i_ctx_p)
130
4.04M
{
131
4.04M
    os_ptr op = osp;
132
4.04M
    uint n, i;
133
4.04M
    es_ptr esp_orig;
134
135
4.04M
    check_op(1);
136
4.04M
    check_int_leu(*op, max_uint - 1);
137
4.04M
    n = (uint) op->value.intval;
138
4.04M
    check_op(n + 1);
139
4.04M
    check_estack(n);
140
4.04M
    esp_orig = esp;
141
15.4M
    for (i = 0; i < n; ++i) {
142
11.4M
        const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
143
144
11.4M
        if (rp == NULL)
145
0
            continue;
146
147
        /* Make sure this object is legal to execute. */
148
11.4M
        if (ref_type_uses_access(r_type(rp))) {
149
5.23M
            if (!r_has_attr(rp, a_execute) &&
150
0
                r_has_attr(rp, a_executable)
151
5.23M
                ) {
152
0
                esp = esp_orig;
153
0
                return_error(gs_error_invalidaccess);
154
0
            }
155
5.23M
        }
156
        /* Executable nulls have a special meaning on the e-stack, */
157
        /* so since they are no-ops, don't push them. */
158
11.4M
        if (!r_has_type_attrs(rp, t_null, a_executable)) {
159
11.4M
            ++esp;
160
11.4M
            ref_assign(esp, rp);
161
11.4M
        }
162
11.4M
    }
163
4.04M
    esfile_check_cache();
164
4.04M
    pop(n + 1);
165
4.04M
    return o_push_estack;
166
4.04M
}
167
168
/* <array> <executable> .runandhide <obj>       */
169
/*  before executing  <executable>, <array> is been removed from  */
170
/*  the operand stack and placed on the execstack with attributes */
171
/*  changed to 'noaccess'.            */
172
/*  After execution, the array will be placed on  the top of the  */
173
/*  operand stack (on top of any elemetns pushed by <executable>  */
174
/*  for both the normal case and for the error case.    */
175
static int end_runandhide(i_ctx_t *);
176
static int err_end_runandhide(i_ctx_t *);
177
static int
178
zrunandhide(i_ctx_t *i_ctx_p)
179
0
{
180
0
    os_ptr op = osp;
181
0
    es_ptr ep;
182
183
0
    check_op(2);
184
0
    if (!r_is_array(op - 1))
185
0
        return_op_typecheck(op);
186
0
    if (!r_has_attr(op, a_executable))
187
0
        return 0;   /* literal object just gets pushed back */
188
0
    check_estack(5);
189
0
    ep = esp += 5;
190
0
    make_mark_estack(ep - 4, es_other, err_end_runandhide); /* error case */
191
0
    make_op_estack(ep - 1,  end_runandhide); /* normal case */
192
0
    ref_assign(ep, op);
193
    /* Store the object we are hiding  and it's current tas.type_attrs */
194
    /* on the exec stack then change to 'noaccess' */
195
0
    make_int(ep - 3, (int)op[-1].tas.type_attrs);
196
0
    ref_assign(ep - 2, op - 1);
197
0
    r_clear_attrs(ep - 2, a_all);
198
    /* replace the array with a special kind of mark that has a_read access */
199
0
    esfile_check_cache();
200
0
    pop(2);
201
0
    return o_push_estack;
202
0
}
203
static int
204
runandhide_restore_hidden(i_ctx_t *i_ctx_p, ref *obj, ref *attrs)
205
0
{
206
0
    os_ptr op = osp;
207
208
0
    push(1);
209
    /* restore the hidden_object and its type_attrs */
210
0
    ref_assign(op, obj);
211
0
    r_clear_attrs(op, a_all);
212
0
    r_set_attrs(op, attrs->value.intval);
213
0
    return 0;
214
0
}
215
216
/* - %end_runandhide hiddenobject */
217
static int
218
end_runandhide(i_ctx_t *i_ctx_p)
219
0
{
220
0
    int code;
221
222
0
    if ((code = runandhide_restore_hidden(i_ctx_p, esp, esp - 1)) < 0) {
223
0
        esp -= 2;
224
0
        return code;
225
0
    }
226
0
    esp -= 2;    /* pop the hidden value and its atributes */
227
0
    return o_pop_estack;
228
0
}
229
230
/* restore hidden object for error returns */
231
static int
232
err_end_runandhide(i_ctx_t *i_ctx_p)
233
0
{
234
0
    int code;
235
236
0
    if ((code = runandhide_restore_hidden(i_ctx_p, esp + 3, esp + 2)) < 0)
237
0
        return code;
238
0
    return 0;
239
0
}
240
241
/* <bool> <proc> if - */
242
int
243
zif(i_ctx_t *i_ctx_p)
244
0
{
245
0
    os_ptr op = osp;
246
247
0
    check_op(2);
248
0
    check_proc(*op);
249
0
    check_type(op[-1], t_boolean);
250
0
    if (op[-1].value.boolval) {
251
0
        check_estack(1);
252
0
        ++esp;
253
0
        ref_assign(esp, op);
254
0
        esfile_check_cache();
255
0
    }
256
0
    pop(2);
257
0
    return o_push_estack;
258
0
}
259
260
/* <bool> <proc_true> <proc_false> ifelse - */
261
int
262
zifelse(i_ctx_t *i_ctx_p)
263
0
{
264
0
    os_ptr op = osp;
265
266
0
    check_op(3);
267
0
    check_proc(*op);
268
0
    check_proc(op[-1]);
269
0
    check_type(op[-2], t_boolean);
270
0
    check_estack(1);
271
0
    ++esp;
272
0
    if (op[-2].value.boolval) {
273
0
        ref_assign(esp, op - 1);
274
0
    } else {
275
0
        ref_assign(esp, op);
276
0
    }
277
0
    esfile_check_cache();
278
0
    pop(3);
279
0
    return o_push_estack;
280
0
}
281
282
/* <init> <step> <limit> <proc> for - */
283
static int
284
    for_pos_int_continue(i_ctx_t *),
285
    for_neg_int_continue(i_ctx_t *),
286
    for_real_continue(i_ctx_t *);
287
int
288
zfor(i_ctx_t *i_ctx_p)
289
29.4M
{
290
29.4M
    os_ptr op = osp;
291
29.4M
    register es_ptr ep;
292
29.4M
    int code;
293
29.4M
    float params[3];
294
295
29.4M
    check_op(4);
296
        /* Mostly undocumented, and somewhat bizarre Adobe behavior discovered  */
297
        /* with the CET (28-05) and FTS (124-01) is that the proc is not run  */
298
        /* if BOTH the initial value and increment are zero.      */
299
29.4M
    if ((code = float_params(op - 1, 3, params)) < 0)
300
10
        return code;
301
29.4M
    if ( params[0] == 0.0 && params[1] == 0.0 ) {
302
80
        pop(4);    /* don't run the proc */
303
80
        return 0;
304
80
    }
305
29.4M
    check_estack(7);
306
29.4M
    ep = esp + 6;
307
29.4M
    check_proc(*op);
308
    /* Push a mark, the control variable set to the initial value, */
309
    /* the increment, the limit, and the procedure, */
310
    /* and invoke the continuation operator. */
311
29.4M
    if (r_has_type(op - 3, t_integer) &&
312
28.1M
        r_has_type(op - 2, t_integer)
313
29.4M
        ) {
314
25.0M
        make_int(ep - 4, op[-3].value.intval);
315
25.0M
        make_int(ep - 3, op[-2].value.intval);
316
25.0M
        switch (r_type(op - 1)) {
317
25.0M
            case t_integer:
318
25.0M
                make_int(ep - 2, op[-1].value.intval);
319
25.0M
                break;
320
17
            case t_real:
321
17
                make_int(ep - 2, (ps_int)op[-1].value.realval);
322
17
                break;
323
0
            default:
324
0
                return_op_typecheck(op - 1);
325
25.0M
        }
326
25.0M
        if (ep[-3].value.intval >= 0)
327
25.0M
            make_op_estack(ep, for_pos_int_continue);
328
19.6M
        else
329
25.0M
            make_op_estack(ep, for_neg_int_continue);
330
25.0M
    } else {
331
4.34M
        make_real(ep - 4, params[0]);
332
4.34M
        make_real(ep - 3, params[1]);
333
4.34M
        make_real(ep - 2, params[2]);
334
4.34M
        make_op_estack(ep, for_real_continue);
335
4.34M
    }
336
29.4M
    make_mark_estack(ep - 5, es_for, no_cleanup);
337
29.4M
    ref_assign(ep - 1, op);
338
29.4M
    esp = ep;
339
29.4M
    pop(4);
340
29.4M
    return o_push_estack;
341
29.4M
}
342
/* Continuation operators for for, separate for positive integer, */
343
/* negative integer, and real. */
344
/* Execution stack contains mark, control variable, increment, */
345
/* limit, and procedure (procedure is topmost.) */
346
/* Continuation operator for positive integers. */
347
static int
348
for_pos_int_continue(i_ctx_t *i_ctx_p)
349
292M
{
350
292M
    os_ptr op = osp;
351
292M
    register es_ptr ep = esp;
352
292M
    ps_int var = ep[-3].value.intval;
353
354
292M
    if (var > ep[-1].value.intval) {
355
5.42M
        esp -= 5;    /* pop everything */
356
5.42M
        return o_pop_estack;
357
5.42M
    }
358
292M
    push(1);
359
286M
    make_int(op, var);
360
286M
    ep[-3].value.intval = var + ep[-2].value.intval;
361
286M
    ref_assign_inline(ep + 2, ep); /* saved proc */
362
286M
    esp = ep + 2;
363
286M
    return o_push_estack;
364
286M
}
365
/* Continuation operator for negative integers. */
366
static int
367
for_neg_int_continue(i_ctx_t *i_ctx_p)
368
156M
{
369
156M
    os_ptr op = osp;
370
156M
    register es_ptr ep = esp;
371
156M
    ps_int var = ep[-3].value.intval;
372
373
156M
    if (var < ep[-1].value.intval) {
374
19.6M
        esp -= 5;    /* pop everything */
375
19.6M
        return o_pop_estack;
376
19.6M
    }
377
156M
    push(1);
378
137M
    make_int(op, var);
379
137M
    ep[-3].value.intval = var + ep[-2].value.intval;
380
137M
    ref_assign(ep + 2, ep); /* saved proc */
381
137M
    esp = ep + 2;
382
137M
    return o_push_estack;
383
137M
}
384
/* Continuation operator for reals. */
385
static int
386
for_real_continue(i_ctx_t *i_ctx_p)
387
8.25M
{
388
8.25M
    os_ptr op = osp;
389
8.25M
    es_ptr ep = esp;
390
8.25M
    float var = ep[-3].value.realval;
391
8.25M
    float incr = ep[-2].value.realval;
392
393
8.25M
    if (incr >= 0 ? (var > ep[-1].value.realval) :
394
8.25M
        (var < ep[-1].value.realval)
395
8.25M
        ) {
396
4.34M
        esp -= 5;    /* pop everything */
397
4.34M
        return o_pop_estack;
398
4.34M
    }
399
8.25M
    push(1);
400
3.90M
    ref_assign(op, ep - 3);
401
3.90M
    ep[-3].value.realval = var + incr;
402
3.90M
    esp = ep + 2;
403
3.90M
    ref_assign(ep + 2, ep); /* saved proc */
404
3.90M
    return o_push_estack;
405
3.91M
}
406
407
/*
408
 * Here we provide an internal variant of 'for' that enumerates the values
409
 * A, ((N-1)*A+1*B)/N, ((N-2)*A+2*B)/N, ..., B precisely.  The arguments are
410
 * A (real), N (integer), and B (real).  We need this for loading caches such
411
 * as the transfer function cache.
412
 *
413
 * NOTE: This computation must match the SAMPLE_LOOP_VALUE macro in gscie.h.
414
 */
415
static int for_samples_continue(i_ctx_t *);
416
/* <first> <count> <last> <proc> %for_samples - */
417
int
418
zfor_samples(i_ctx_t *i_ctx_p)
419
347k
{
420
347k
    os_ptr op = osp;
421
347k
    es_ptr ep;
422
423
347k
    check_op(4);
424
347k
    check_type(op[-3], t_real);
425
347k
    check_type(op[-2], t_integer);
426
347k
    check_type(op[-1], t_real);
427
347k
    check_proc(*op);
428
347k
    check_estack(8);
429
347k
    ep = esp + 7;
430
347k
    make_mark_estack(ep - 6, es_for, no_cleanup);
431
347k
    make_int(ep - 5, 0);
432
347k
    memcpy(ep - 4, op - 3, 3 * sizeof(ref));
433
347k
    ref_assign(ep - 1, op);
434
347k
    make_op_estack(ep, for_samples_continue);
435
347k
    esp = ep;
436
347k
    pop(4);
437
347k
    return o_push_estack;
438
347k
}
439
/* Continuation procedure */
440
static int
441
for_samples_continue(i_ctx_t *i_ctx_p)
442
89.2M
{
443
89.2M
    os_ptr op = osp;
444
89.2M
    es_ptr ep = esp;
445
89.2M
    int var = ep[-4].value.intval;
446
89.2M
    float a = ep[-3].value.realval;
447
89.2M
    int n = ep[-2].value.intval;
448
89.2M
    float b = ep[-1].value.realval;
449
450
89.2M
    if (var > n) {
451
347k
        esp -= 6;    /* pop everything */
452
347k
        return o_pop_estack;
453
347k
    }
454
89.2M
    push(1);
455
88.8M
    make_real(op, ((n - var) * a + var * b) / n);
456
88.8M
    ep[-4].value.intval = var + 1;
457
88.8M
    ref_assign_inline(ep + 2, ep); /* saved proc */
458
88.8M
    esp = ep + 2;
459
88.8M
    return o_push_estack;
460
88.8M
}
461
462
/* <int> <proc> repeat - */
463
static int repeat_continue(i_ctx_t *);
464
int
465
zrepeat(i_ctx_t *i_ctx_p)
466
7.33M
{
467
7.33M
    os_ptr op = osp;
468
469
7.33M
    check_op(2);
470
7.33M
    check_proc(*op);
471
7.33M
    check_type(op[-1], t_integer);
472
7.33M
    if (op[-1].value.intval < 0)
473
0
        return_error(gs_error_rangecheck);
474
7.33M
    check_estack(5);
475
    /* Push a mark, the count, and the procedure, and invoke */
476
    /* the continuation operator. */
477
7.33M
    push_mark_estack(es_for, no_cleanup);
478
7.33M
    *++esp = op[-1];
479
7.33M
    *++esp = *op;
480
7.33M
    make_op_estack(esp + 1, repeat_continue);
481
7.33M
    pop(2);
482
7.33M
    return repeat_continue(i_ctx_p);
483
7.33M
}
484
/* Continuation operator for repeat */
485
static int
486
repeat_continue(i_ctx_t *i_ctx_p)
487
241M
{
488
241M
    es_ptr ep = esp;   /* saved proc */
489
490
241M
    if (--(ep[-1].value.intval) >= 0) {   /* continue */
491
233M
        esp += 2;
492
233M
        ref_assign(esp, ep);
493
233M
        return o_push_estack;
494
233M
    } else {     /* done */
495
7.31M
        esp -= 3;    /* pop mark, count, proc */
496
7.31M
        return o_pop_estack;
497
7.31M
    }
498
241M
}
499
500
/* <proc> loop */
501
static int loop_continue(i_ctx_t *);
502
static int
503
zloop(i_ctx_t *i_ctx_p)
504
18.6M
{
505
18.6M
    os_ptr op = osp;
506
507
18.6M
    check_op(1);
508
18.6M
    check_proc(*op);
509
18.6M
    check_estack(4);
510
    /* Push a mark and the procedure, and invoke */
511
    /* the continuation operator. */
512
18.6M
    push_mark_estack(es_for, no_cleanup);
513
18.6M
    *++esp = *op;
514
18.6M
    make_op_estack(esp + 1, loop_continue);
515
18.6M
    pop(1);
516
18.6M
    return loop_continue(i_ctx_p);
517
18.6M
}
518
/* Continuation operator for loop */
519
static int
520
loop_continue(i_ctx_t *i_ctx_p)
521
174M
{
522
174M
    register es_ptr ep = esp; /* saved proc */
523
524
174M
    ref_assign(ep + 2, ep);
525
174M
    esp = ep + 2;
526
174M
    return o_push_estack;
527
174M
}
528
529
/* - exit - */
530
static int
531
zexit(i_ctx_t *i_ctx_p)
532
18.8M
{
533
18.8M
    os_ptr op = osp;
534
18.8M
    ref_stack_enum_t rsenum;
535
18.8M
    uint scanned = 0;
536
537
18.8M
    ref_stack_enum_begin(&rsenum, &e_stack);
538
18.8M
    do {
539
18.8M
        uint used = rsenum.size;
540
18.8M
        es_ptr ep = rsenum.ptr + used - 1;
541
18.8M
        uint count = used;
542
543
75.0M
        for (; count; count--, ep--)
544
75.0M
            if (r_is_estack_mark(ep))
545
18.8M
                switch (estack_mark_index(ep)) {
546
18.8M
                    case es_for:
547
18.8M
                        pop_estack(i_ctx_p, scanned + (used - count + 1));
548
18.8M
                        return o_pop_estack;
549
12
                    case es_stopped:
550
12
                        return_error(gs_error_invalidexit); /* not a loop */
551
18.8M
                }
552
0
        scanned += used;
553
0
    } while (ref_stack_enum_next(&rsenum));
554
    /* No mark, quit.  (per Adobe documentation) */
555
18.8M
    push(2);
556
0
    return unmatched_exit(op, zexit);
557
0
}
558
559
/*
560
 * .stopped pushes the following on the e-stack:
561
 *      - A mark with type = es_stopped and procedure = no_cleanup.
562
 *      - The result to be pushed on a normal return.
563
 *      - The signal mask for .stop.
564
 *      - The procedure %stopped_push, to handle the normal return case.
565
 */
566
567
/* In the normal (no-error) case, pop the mask from the e-stack, */
568
/* and move the result to the o-stack. */
569
static int
570
stopped_push(i_ctx_t *i_ctx_p)
571
16.7M
{
572
16.7M
    os_ptr op = osp;
573
574
16.7M
    push(1);
575
16.7M
    *op = esp[-1];
576
16.7M
    esp -= 3;
577
16.7M
    return o_pop_estack;
578
16.7M
}
579
580
/* - stop - */
581
/* Equivalent to true 1 .stop. */
582
/* This is implemented in C because if were a pseudo-operator, */
583
/* the stacks would get restored in case of an error. */
584
static int
585
zstop(i_ctx_t *i_ctx_p)
586
99.9M
{
587
99.9M
    os_ptr op = osp;
588
99.9M
    uint count = count_to_stopped(i_ctx_p, 1L);
589
590
99.9M
    if (count) {
591
        /*
592
         * If there are any t_oparrays on the e-stack, they will pop
593
         * any new items from the o-stack.  Wait to push the 'true'
594
         * until we have run all the unwind procedures.
595
         */
596
99.9M
        check_ostack(2);
597
99.9M
        pop_estack(i_ctx_p, count);
598
99.9M
        op = osp;
599
99.9M
        push(1);
600
99.9M
        make_true(op);
601
99.9M
        return o_pop_estack;
602
99.9M
    }
603
    /* No mark, quit.  (per Adobe documentation) */
604
99.9M
    push(2);
605
44.0k
    return unmatched_exit(op, zstop);
606
44.0k
}
607
608
/* <result> <mask> .stop - */
609
static int
610
zzstop(i_ctx_t *i_ctx_p)
611
3.62k
{
612
3.62k
    os_ptr op = osp;
613
3.62k
    uint count;
614
615
3.62k
    check_op(2);
616
3.62k
    check_type(*op, t_integer);
617
3.62k
    count = count_to_stopped(i_ctx_p, op->value.intval);
618
3.62k
    if (count) {
619
        /*
620
         * If there are any t_oparrays on the e-stack, they will pop
621
         * any new items from the o-stack.  Wait to push the result
622
         * until we have run all the unwind procedures.
623
         */
624
3.62k
        ref save_result;
625
626
3.62k
        check_op(2);
627
3.62k
        save_result = op[-1];
628
3.62k
        pop(2);
629
3.62k
        pop_estack(i_ctx_p, count);
630
3.62k
        op = osp;
631
3.62k
        push(1);
632
3.62k
        *op = save_result;
633
3.62k
        return o_pop_estack;
634
3.62k
    }
635
    /* No mark, quit.  (per Adobe documentation) */
636
0
    return unmatched_exit(op, zzstop);
637
3.62k
}
638
639
/* <obj> stopped <stopped> */
640
/* Equivalent to false 1 .stopped. */
641
/* This is implemented in C because if were a pseudo-operator, */
642
/* the stacks would get restored in case of an error. */
643
static int
644
zstopped(i_ctx_t *i_ctx_p)
645
7.35M
{
646
7.35M
    os_ptr op = osp;
647
648
7.35M
    check_op(1);
649
    /* Mark the execution stack, and push the default result */
650
    /* in case control returns normally. */
651
7.35M
    check_estack(5);
652
7.35M
    push_mark_estack(es_stopped, no_cleanup);
653
7.35M
    ++esp;
654
7.35M
    make_false(esp);    /* save the result */
655
7.35M
    ++esp;
656
7.35M
    make_int(esp, 1);   /* save the signal mask */
657
7.35M
    push_op_estack(stopped_push);
658
7.35M
    push_op_estack(zexec);  /* execute the operand */
659
7.35M
    return o_push_estack;
660
7.35M
}
661
662
/* <obj> <result> <mask> .stopped <result> */
663
static int
664
zzstopped(i_ctx_t *i_ctx_p)
665
109M
{
666
109M
    os_ptr op = osp;
667
109M
    check_type(*op, t_integer);
668
109M
    check_op(3);
669
    /* Mark the execution stack, and push the default result */
670
    /* in case control returns normally. */
671
109M
    check_estack(5);
672
109M
    push_mark_estack(es_stopped, no_cleanup);
673
109M
    *++esp = op[-1];    /* save the result */
674
109M
    *++esp = *op;   /* save the signal mask */
675
109M
    push_op_estack(stopped_push);
676
109M
    push_op_estack(zexec);  /* execute the operand */
677
109M
    pop(2);
678
109M
    return o_push_estack;
679
109M
}
680
681
/* <mask> .instopped false */
682
/* <mask> .instopped <result> true */
683
static int
684
zinstopped(i_ctx_t *i_ctx_p)
685
99.8M
{
686
99.8M
    os_ptr op = osp;
687
99.8M
    uint count;
688
689
99.8M
    check_type(*op, t_integer);
690
99.8M
    count = count_to_stopped(i_ctx_p, op->value.intval);
691
99.8M
    if (count) {
692
99.8M
        push(1);
693
99.8M
        op[-1] = *ref_stack_index(&e_stack, count - 2);   /* default result */
694
99.8M
        make_true(op);
695
99.8M
    } else
696
99.8M
        make_false(op);
697
99.8M
    return 0;
698
99.8M
}
699
700
/* <include_marks> .countexecstack <int> */
701
/* - countexecstack <int> */
702
/* countexecstack is an operator solely for the sake of the Genoa tests. */
703
static int
704
zcountexecstack(i_ctx_t *i_ctx_p)
705
204k
{
706
204k
    os_ptr op = osp;
707
708
204k
    push(1);
709
204k
    make_int(op, count_exec_stack(i_ctx_p, false));
710
204k
    return 0;
711
204k
}
712
static int
713
zcountexecstack1(i_ctx_t *i_ctx_p)
714
9.69k
{
715
9.69k
    os_ptr op = osp;
716
717
9.69k
    check_type(*op, t_boolean);
718
9.69k
    make_int(op, count_exec_stack(i_ctx_p, op->value.boolval));
719
9.69k
    return 0;
720
9.69k
}
721
722
/* <array> <include_marks> .execstack <subarray> */
723
/* <array> execstack <subarray> */
724
/* execstack is an operator solely for the sake of the Genoa tests. */
725
static int execstack_continue(i_ctx_t *);
726
static int execstack2_continue(i_ctx_t *);
727
static int
728
push_execstack(i_ctx_t *i_ctx_p, os_ptr op1, bool include_marks,
729
               op_proc_t cont)
730
214k
{
731
214k
    uint size;
732
    /*
733
     * We can't do this directly, because the interpreter
734
     * might have cached some state.  To force the interpreter
735
     * to update the stored state, we push a continuation on
736
     * the exec stack; the continuation is executed immediately,
737
     * and does the actual transfer.
738
     */
739
214k
    uint depth;
740
741
214k
    if (!r_is_array(op1))
742
214k
        return_op_typecheck(op1);
743
    /* Check the length before the write access per CET 28-03 */
744
214k
    size = r_size(op1);
745
214k
    depth = count_exec_stack(i_ctx_p, include_marks);
746
214k
    if (depth > size)
747
0
        return_error(gs_error_rangecheck);
748
214k
    check_write(*op1);
749
214k
    {
750
214k
        int code = ref_stack_store_check(&e_stack, op1, size, 0);
751
752
214k
        if (code < 0)
753
0
            return code;
754
214k
    }
755
214k
    check_estack(1);
756
214k
    r_set_size(op1, depth);
757
214k
    push_op_estack(cont);
758
214k
    return o_push_estack;
759
214k
}
760
static int
761
zexecstack(i_ctx_t *i_ctx_p)
762
204k
{
763
204k
    os_ptr op = osp;
764
765
204k
    return push_execstack(i_ctx_p, op, false, execstack_continue);
766
204k
}
767
static int
768
zexecstack2(i_ctx_t *i_ctx_p)
769
9.69k
{
770
9.69k
    os_ptr op = osp;
771
772
9.69k
    check_type(*op, t_boolean);
773
9.69k
    return push_execstack(i_ctx_p, op - 1, op->value.boolval, execstack2_continue);
774
9.69k
}
775
/* Continuation operator to do the actual transfer. */
776
/* r_size(op1) was set just above. */
777
static int
778
do_execstack(i_ctx_t *i_ctx_p, bool include_marks, bool include_oparrays, os_ptr op1)
779
214k
{
780
214k
    os_ptr op = osp;
781
214k
    ref *arefs = op1->value.refs;
782
214k
    uint asize = r_size(op1);
783
214k
    uint i;
784
214k
    ref *rq;
785
786
    /*
787
     * Copy elements from the stack to the array,
788
     * optionally skipping executable nulls.
789
     * Clear the executable bit in any internal operators, and
790
     * convert t_structs and t_astructs (which can only appear
791
     * in connection with stack marks, which means that they will
792
     * probably be freed when unwinding) to something harmless.
793
     */
794
18.1M
    for (i = 0, rq = arefs + asize; rq != arefs; ++i) {
795
17.9M
        const ref *rp = ref_stack_index(&e_stack, (long)i);
796
797
17.9M
        if (rp == NULL)
798
0
            continue;
799
17.9M
        if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks)
800
2.99M
            continue;
801
14.9M
        --rq;
802
14.9M
        ref_assign_old(op1, rq, rp, "execstack");
803
14.9M
        switch (r_type(rq)) {
804
3.20M
            case t_operator: {
805
3.20M
                uint opidx = op_index(rq);
806
807
3.20M
                if (opidx == 0 || op_def_is_internal(op_index_def(opidx)))
808
3.20M
                    r_clear_attrs(rq, a_executable);
809
3.20M
                break;
810
0
            }
811
1.27k
            case t_struct:
812
1.27k
            case t_astruct: {
813
1.27k
                const char *tname = rq->value.pstruct ?
814
1.27k
                    gs_struct_type_name_string(
815
1.27k
                                gs_object_type(imemory, rq->value.pstruct))
816
1.27k
                    : "NULL";
817
818
1.27k
                make_const_string(rq, a_readonly | avm_foreign,
819
1.27k
                                  strlen(tname), (const byte *)tname);
820
1.27k
                break;
821
1.27k
            }
822
212k
            case t_array:
823
343k
            case t_shortarray:
824
3.75M
            case t_mixedarray:
825
3.75M
                if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0)
826
3.75M
                    make_null(rq);
827
3.75M
                break;
828
7.99M
            default:
829
7.99M
                ;
830
14.9M
        }
831
14.9M
    }
832
214k
    pop(op - op1);
833
214k
    return 0;
834
214k
}
835
static int
836
execstack_continue(i_ctx_t *i_ctx_p)
837
204k
{
838
204k
    os_ptr op = osp;
839
840
204k
    return do_execstack(i_ctx_p, false, false, op);
841
204k
}
842
static int
843
execstack2_continue(i_ctx_t *i_ctx_p)
844
9.69k
{
845
9.69k
    os_ptr op = osp;
846
847
9.69k
    return do_execstack(i_ctx_p, op->value.boolval, true, op - 1);
848
9.69k
}
849
850
/* - .needinput - */
851
static int
852
zneedinput(i_ctx_t *i_ctx_p)
853
1.60M
{
854
1.60M
    return gs_error_NeedInput;    /* interpreter will exit to caller */
855
1.60M
}
856
857
/* <obj> <int> .quit - */
858
static int
859
zquit(i_ctx_t *i_ctx_p)
860
578k
{
861
578k
    os_ptr op = osp;
862
863
578k
    check_op(2);
864
578k
    check_type(*op, t_integer);
865
578k
    return_error(gs_error_Quit);  /* Interpreter will do the exit */
866
578k
}
867
868
/* Get the current file from which the interpreter is reading. */
869
static ref *
870
zget_current_file(i_ctx_t *i_ctx_p)
871
341k
{
872
341k
    ref_stack_enum_t rsenum;
873
874
341k
    ref_stack_enum_begin(&rsenum, &e_stack);
875
341k
    do {
876
341k
        uint count = rsenum.size;
877
341k
        es_ptr ep = rsenum.ptr + count - 1;
878
879
15.7M
        for (; count; count--, ep--)
880
15.7M
            if (r_has_type_attrs(ep, t_file, a_executable))
881
341k
                return ep;
882
341k
    } while (ref_stack_enum_next(&rsenum));
883
0
    return 0;
884
341k
}
885
886
/* - currentfile <file> */
887
int
888
z_current_file(i_ctx_t *i_ctx_p, ref **s)
889
110M
{
890
110M
    ref *fp;
891
    /* Check the cache first */
892
110M
    if (esfile != 0) {
893
#ifdef DEBUG
894
        /* Check that esfile is valid. */
895
        ref *efp = zget_current_file(i_ctx_p);
896
897
        if (esfile != efp) {
898
            lprintf2("currentfile: esfile="PRI_INTPTR", efp="PRI_INTPTR"\n",
899
                     (intptr_t) esfile, (intptr_t) efp);
900
            *s = efp;
901
        } else
902
#endif
903
109M
            *s = esfile;
904
109M
    } else if ((fp = zget_current_file(i_ctx_p)) == 0) { /* Return an invalid file object. */
905
0
        *s = NULL;
906
341k
    } else {
907
341k
        *s = fp;
908
341k
        esfile_set_cache(fp);
909
341k
    }
910
110M
    return 0;
911
110M
}
912
static int
913
zcurrentfile(i_ctx_t *i_ctx_p)
914
110M
{
915
110M
    os_ptr op = osp;
916
110M
    ref *s;
917
110M
    int code;
918
919
110M
    push(1);
920
921
110M
    code = z_current_file(i_ctx_p, &s);
922
110M
    if (code < 0 || s == NULL) {
923
        /* This doesn't make a lot of sense to me, */
924
        /* but it's what the PostScript manual specifies. */
925
0
        make_invalid_file(i_ctx_p, op);
926
0
    }
927
110M
    else {
928
110M
        ref_assign(op, s);
929
110M
    }
930
    /* Make the returned value literal. */
931
110M
    r_clear_attrs(op, a_executable);
932
110M
    return code;
933
110M
}
934
/* ------ Initialization procedure ------ */
935
936
/* We need to split the table because of the 16-element limit. */
937
const op_def zcontrol1_op_defs[] = {
938
    {"1.cond", zcond},
939
    {"0countexecstack", zcountexecstack},
940
    {"1.countexecstack", zcountexecstack1},
941
    {"0currentfile", zcurrentfile},
942
    {"1exec", zexec},
943
    {"1.execn", zexecn},
944
    {"1execstack", zexecstack},
945
    {"2.execstack", zexecstack2},
946
    {"0exit", zexit},
947
    {"2if", zif},
948
    {"3ifelse", zifelse},
949
    {"0.instopped", zinstopped},
950
    {"0.needinput", zneedinput},
951
    op_def_end(0)
952
};
953
const op_def zcontrol2_op_defs[] = {
954
    {"4for", zfor},
955
    {"1loop", zloop},
956
    {"2.quit", zquit},
957
    {"2repeat", zrepeat},
958
    {"0stop", zstop},
959
    {"1.stop", zzstop},
960
    {"1stopped", zstopped},
961
    {"2.stopped", zzstopped},
962
    op_def_end(0)
963
};
964
const op_def zcontrol3_op_defs[] = {
965
                /* Internal operators */
966
    {"1%cond_continue", cond_continue},
967
    {"1%execstack_continue", execstack_continue},
968
    {"2%execstack2_continue", execstack2_continue},
969
    {"0%for_pos_int_continue", for_pos_int_continue},
970
    {"0%for_neg_int_continue", for_neg_int_continue},
971
    {"0%for_real_continue", for_real_continue},
972
    {"4%for_samples", zfor_samples},
973
    {"0%for_samples_continue", for_samples_continue},
974
    {"0%loop_continue", loop_continue},
975
    {"0%repeat_continue", repeat_continue},
976
    {"0%stopped_push", stopped_push},
977
    {"2.runandhide", zrunandhide},
978
    {"0%end_runandhide", end_runandhide},
979
    op_def_end(0)
980
};
981
982
/* ------ Internal routines ------ */
983
984
/*
985
 * Check the operand of exec or stopped.  Return 0 if OK to execute, or a
986
 * negative error code.  We emulate an apparent bug in Adobe interpreters,
987
 * which cause an invalidaccess error when 'exec'ing a noaccess literal
988
 * (other than dictionaries).  We also match the Adobe interpreters in that
989
 * we catch noaccess executable objects here, rather than waiting for the
990
 * interpreter to catch them, so that we can signal the error with the
991
 * object still on the operand stack.
992
 */
993
static int
994
check_for_exec(const_os_ptr op)
995
1.85G
{
996
1.85G
    if (!r_has_attr(op, a_execute) && /* only true if noaccess */
997
1.85G
        ref_type_uses_access(r_type(op)) &&
998
0
        (r_has_attr(op, a_executable) || !r_has_type(op, t_dictionary))
999
1.85G
        ) {
1000
0
        return_error(gs_error_invalidaccess);
1001
0
    }
1002
1.85G
    return 0;
1003
1.85G
}
1004
1005
/* Vacuous cleanup routine */
1006
static int
1007
no_cleanup(i_ctx_t *i_ctx_p)
1008
118M
{
1009
118M
    return 0;
1010
118M
}
1011
1012
/*
1013
 * Count the number of elements on the exec stack, with or without
1014
 * the normally invisible elements (*op is a Boolean that indicates this).
1015
 */
1016
static uint
1017
count_exec_stack(i_ctx_t *i_ctx_p, bool include_marks)
1018
429k
{
1019
429k
    uint count = ref_stack_count(&e_stack);
1020
1021
429k
    if (!include_marks) {
1022
429k
        uint i;
1023
1024
36.3M
        for (i = count; i--;) {
1025
35.9M
            ref *o;
1026
35.9M
            o = ref_stack_index(&e_stack, (long)i);
1027
35.9M
            if (o == NULL)
1028
0
                continue;
1029
35.9M
            if (r_has_type_attrs(o, t_null, a_executable))
1030
5.98M
                --count;
1031
35.9M
        }
1032
429k
    }
1033
429k
    return count;
1034
429k
}
1035
1036
/*
1037
 * Count the number of elements down to and including the first 'stopped'
1038
 * mark on the e-stack with a given mask.  Return 0 if there is no 'stopped'
1039
 * mark.
1040
 */
1041
static uint
1042
count_to_stopped(i_ctx_t *i_ctx_p, long mask)
1043
199M
{
1044
199M
    ref_stack_enum_t rsenum;
1045
199M
    uint scanned = 0;
1046
1047
199M
    ref_stack_enum_begin(&rsenum, &e_stack);
1048
199M
    do {
1049
199M
        uint used = rsenum.size;
1050
199M
        es_ptr ep = rsenum.ptr + used - 1;
1051
199M
        uint count = used;
1052
1053
2.10G
        for (; count; count--, ep--) {
1054
2.10G
            if (r_is_estack_mark(ep)) {
1055
391M
                if (estack_mark_index(ep) == es_stopped &&
1056
199M
                  (ep[2].value.intval & mask) != 0)
1057
199M
                    return scanned + (used - count + 1);
1058
391M
            }
1059
2.10G
        }
1060
45.1k
        scanned += used;
1061
45.1k
    } while (ref_stack_enum_next(&rsenum));
1062
45.1k
    return 0;
1063
199M
}
1064
1065
/*
1066
 * Pop the e-stack, executing cleanup procedures as needed.
1067
 * We could make this more efficient using ref_stack_enum_*,
1068
 * but it isn't used enough to make this worthwhile.
1069
 */
1070
void
1071
pop_estack(i_ctx_t *i_ctx_p, uint count)
1072
118M
{
1073
118M
    uint idx = 0;
1074
118M
    uint popped = 0;
1075
1076
118M
    esfile_clear_cache();
1077
1.24G
    for (; idx < count; idx++) {
1078
1.12G
        ref *ep = ref_stack_index(&e_stack, idx - popped);
1079
1080
1.12G
        if (ep == NULL)
1081
0
            continue;
1082
1083
1.12G
        if (r_is_estack_mark(ep)) {
1084
            /* This exec stack juggling is to cope with hitting
1085
               exactly the bottom of a stack block. It is possible
1086
               to end up with the book keeping at the bottom of
1087
               one block, and the opproc at the top of the previous
1088
               block. If we pop everything in one go, the book keeping
1089
               entries disappear, so we pop to the start of the book
1090
               keeping values, call the cleanup, then pop the final
1091
               entry.
1092
             */
1093
214M
            op_proc_t opproc = real_opproc(ep);
1094
214M
            ref_stack_pop(&e_stack, idx - popped);
1095
214M
            esp--;
1096
214M
            (*opproc) (i_ctx_p);
1097
214M
            esp++;
1098
214M
            ref_stack_pop(&e_stack, 1);
1099
214M
            popped = idx + 1;
1100
214M
        }
1101
1.12G
    }
1102
118M
    ref_stack_pop(&e_stack, count - popped);
1103
118M
}
1104
1105
/*
1106
 * Execute a quit in the case of an exit or stop with no appropriate
1107
 * enclosing control scope (loop or stopped).  The caller has already
1108
 * ensured two free slots on the top of the o-stack.
1109
 */
1110
static int
1111
unmatched_exit(os_ptr op, op_proc_t opproc)
1112
44.0k
{
1113
44.0k
    make_oper(op - 1, 0, opproc);
1114
44.0k
    make_int(op, gs_error_invalidexit);
1115
44.0k
    return_error(gs_error_Quit);
1116
44.0k
}