Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/psi/zcontrol.c
Line
Count
Source (jump to first uncovered line)
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
138M
{
108
138M
    os_ptr op = osp;
109
138M
    int code;
110
111
138M
    check_op(1);
112
138M
    code = check_for_exec(op);
113
138M
    if (code < 0) {
114
0
        return code;
115
0
    }
116
138M
    if (!r_has_attr(op, a_executable)) {
117
471k
        return 0; /* shortcut, literal object just gets pushed back */
118
471k
    }
119
137M
    check_estack(1);
120
137M
    ++esp;
121
137M
    ref_assign(esp, op);
122
137M
    esfile_check_cache();
123
137M
    pop(1);
124
137M
    return o_push_estack;
125
137M
}
126
127
/* <obj1> ... <objn> <n> .execn - */
128
static int
129
zexecn(i_ctx_t *i_ctx_p)
130
273k
{
131
273k
    os_ptr op = osp;
132
273k
    uint n, i;
133
273k
    es_ptr esp_orig;
134
135
273k
    check_op(1);
136
273k
    check_int_leu(*op, max_uint - 1);
137
273k
    n = (uint) op->value.intval;
138
273k
    check_op(n + 1);
139
273k
    check_estack(n);
140
273k
    esp_orig = esp;
141
1.06M
    for (i = 0; i < n; ++i) {
142
790k
        const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
143
144
790k
        if (rp == NULL)
145
0
            continue;
146
147
        /* Make sure this object is legal to execute. */
148
790k
        if (ref_type_uses_access(r_type(rp))) {
149
350k
            if (!r_has_attr(rp, a_execute) &&
150
350k
                r_has_attr(rp, a_executable)
151
350k
                ) {
152
0
                esp = esp_orig;
153
0
                return_error(gs_error_invalidaccess);
154
0
            }
155
350k
        }
156
        /* Executable nulls have a special meaning on the e-stack, */
157
        /* so since they are no-ops, don't push them. */
158
790k
        if (!r_has_type_attrs(rp, t_null, a_executable)) {
159
790k
            ++esp;
160
790k
            ref_assign(esp, rp);
161
790k
        }
162
790k
    }
163
273k
    esfile_check_cache();
164
273k
    pop(n + 1);
165
273k
    return o_push_estack;
166
273k
}
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
3.65M
{
290
3.65M
    os_ptr op = osp;
291
3.65M
    register es_ptr ep;
292
3.65M
    int code;
293
3.65M
    float params[3];
294
295
3.65M
    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
3.65M
    if ((code = float_params(op - 1, 3, params)) < 0)
300
0
        return code;
301
3.65M
    if ( params[0] == 0.0 && params[1] == 0.0 ) {
302
11
        pop(4);    /* don't run the proc */
303
11
        return 0;
304
11
    }
305
3.65M
    check_estack(7);
306
3.65M
    ep = esp + 6;
307
3.65M
    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
3.65M
    if (r_has_type(op - 3, t_integer) &&
312
3.65M
        r_has_type(op - 2, t_integer)
313
3.65M
        ) {
314
2.03M
        make_int(ep - 4, op[-3].value.intval);
315
2.03M
        make_int(ep - 3, op[-2].value.intval);
316
2.03M
        switch (r_type(op - 1)) {
317
2.03M
            case t_integer:
318
2.03M
                make_int(ep - 2, op[-1].value.intval);
319
2.03M
                break;
320
3
            case t_real:
321
3
                make_int(ep - 2, (ps_int)op[-1].value.realval);
322
3
                break;
323
0
            default:
324
0
                return_op_typecheck(op - 1);
325
2.03M
        }
326
2.03M
        if (ep[-3].value.intval >= 0)
327
2.03M
            make_op_estack(ep, for_pos_int_continue);
328
1.45M
        else
329
2.03M
            make_op_estack(ep, for_neg_int_continue);
330
2.03M
    } else {
331
1.61M
        make_real(ep - 4, params[0]);
332
1.61M
        make_real(ep - 3, params[1]);
333
1.61M
        make_real(ep - 2, params[2]);
334
1.61M
        make_op_estack(ep, for_real_continue);
335
1.61M
    }
336
3.65M
    make_mark_estack(ep - 5, es_for, no_cleanup);
337
3.65M
    ref_assign(ep - 1, op);
338
3.65M
    esp = ep;
339
3.65M
    pop(4);
340
3.65M
    return o_push_estack;
341
3.65M
}
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
26.4M
{
350
26.4M
    os_ptr op = osp;
351
26.4M
    register es_ptr ep = esp;
352
26.4M
    ps_int var = ep[-3].value.intval;
353
354
26.4M
    if (var > ep[-1].value.intval) {
355
581k
        esp -= 5;    /* pop everything */
356
581k
        return o_pop_estack;
357
581k
    }
358
26.4M
    push(1);
359
25.8M
    make_int(op, var);
360
25.8M
    ep[-3].value.intval = var + ep[-2].value.intval;
361
25.8M
    ref_assign_inline(ep + 2, ep); /* saved proc */
362
25.8M
    esp = ep + 2;
363
25.8M
    return o_push_estack;
364
25.8M
}
365
/* Continuation operator for negative integers. */
366
static int
367
for_neg_int_continue(i_ctx_t *i_ctx_p)
368
12.5M
{
369
12.5M
    os_ptr op = osp;
370
12.5M
    register es_ptr ep = esp;
371
12.5M
    ps_int var = ep[-3].value.intval;
372
373
12.5M
    if (var < ep[-1].value.intval) {
374
1.45M
        esp -= 5;    /* pop everything */
375
1.45M
        return o_pop_estack;
376
1.45M
    }
377
12.5M
    push(1);
378
11.0M
    make_int(op, var);
379
11.0M
    ep[-3].value.intval = var + ep[-2].value.intval;
380
11.0M
    ref_assign(ep + 2, ep); /* saved proc */
381
11.0M
    esp = ep + 2;
382
11.0M
    return o_push_estack;
383
11.0M
}
384
/* Continuation operator for reals. */
385
static int
386
for_real_continue(i_ctx_t *i_ctx_p)
387
3.02M
{
388
3.02M
    os_ptr op = osp;
389
3.02M
    es_ptr ep = esp;
390
3.02M
    float var = ep[-3].value.realval;
391
3.02M
    float incr = ep[-2].value.realval;
392
393
3.02M
    if (incr >= 0 ? (var > ep[-1].value.realval) :
394
3.02M
        (var < ep[-1].value.realval)
395
3.02M
        ) {
396
1.61M
        esp -= 5;    /* pop everything */
397
1.61M
        return o_pop_estack;
398
1.61M
    }
399
3.02M
    push(1);
400
1.40M
    ref_assign(op, ep - 3);
401
1.40M
    ep[-3].value.realval = var + incr;
402
1.40M
    esp = ep + 2;
403
1.40M
    ref_assign(ep + 2, ep); /* saved proc */
404
1.40M
    return o_push_estack;
405
1.40M
}
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
32.4k
{
420
32.4k
    os_ptr op = osp;
421
32.4k
    es_ptr ep;
422
423
32.4k
    check_op(4);
424
32.4k
    check_type(op[-3], t_real);
425
32.4k
    check_type(op[-2], t_integer);
426
32.4k
    check_type(op[-1], t_real);
427
32.4k
    check_proc(*op);
428
32.4k
    check_estack(8);
429
32.4k
    ep = esp + 7;
430
32.4k
    make_mark_estack(ep - 6, es_for, no_cleanup);
431
32.4k
    make_int(ep - 5, 0);
432
32.4k
    memcpy(ep - 4, op - 3, 3 * sizeof(ref));
433
32.4k
    ref_assign(ep - 1, op);
434
32.4k
    make_op_estack(ep, for_samples_continue);
435
32.4k
    esp = ep;
436
32.4k
    pop(4);
437
32.4k
    return o_push_estack;
438
32.4k
}
439
/* Continuation procedure */
440
static int
441
for_samples_continue(i_ctx_t *i_ctx_p)
442
8.34M
{
443
8.34M
    os_ptr op = osp;
444
8.34M
    es_ptr ep = esp;
445
8.34M
    int var = ep[-4].value.intval;
446
8.34M
    float a = ep[-3].value.realval;
447
8.34M
    int n = ep[-2].value.intval;
448
8.34M
    float b = ep[-1].value.realval;
449
450
8.34M
    if (var > n) {
451
32.4k
        esp -= 6;    /* pop everything */
452
32.4k
        return o_pop_estack;
453
32.4k
    }
454
8.34M
    push(1);
455
8.31M
    make_real(op, ((n - var) * a + var * b) / n);
456
8.31M
    ep[-4].value.intval = var + 1;
457
8.31M
    ref_assign_inline(ep + 2, ep); /* saved proc */
458
8.31M
    esp = ep + 2;
459
8.31M
    return o_push_estack;
460
8.31M
}
461
462
/* <int> <proc> repeat - */
463
static int repeat_continue(i_ctx_t *);
464
int
465
zrepeat(i_ctx_t *i_ctx_p)
466
1.43M
{
467
1.43M
    os_ptr op = osp;
468
469
1.43M
    check_op(2);
470
1.43M
    check_proc(*op);
471
1.43M
    check_type(op[-1], t_integer);
472
1.43M
    if (op[-1].value.intval < 0)
473
0
        return_error(gs_error_rangecheck);
474
1.43M
    check_estack(5);
475
    /* Push a mark, the count, and the procedure, and invoke */
476
    /* the continuation operator. */
477
1.43M
    push_mark_estack(es_for, no_cleanup);
478
1.43M
    *++esp = op[-1];
479
1.43M
    *++esp = *op;
480
1.43M
    make_op_estack(esp + 1, repeat_continue);
481
1.43M
    pop(2);
482
1.43M
    return repeat_continue(i_ctx_p);
483
1.43M
}
484
/* Continuation operator for repeat */
485
static int
486
repeat_continue(i_ctx_t *i_ctx_p)
487
23.6M
{
488
23.6M
    es_ptr ep = esp;   /* saved proc */
489
490
23.6M
    if (--(ep[-1].value.intval) >= 0) {   /* continue */
491
22.1M
        esp += 2;
492
22.1M
        ref_assign(esp, ep);
493
22.1M
        return o_push_estack;
494
22.1M
    } else {     /* done */
495
1.43M
        esp -= 3;    /* pop mark, count, proc */
496
1.43M
        return o_pop_estack;
497
1.43M
    }
498
23.6M
}
499
500
/* <proc> loop */
501
static int loop_continue(i_ctx_t *);
502
static int
503
zloop(i_ctx_t *i_ctx_p)
504
1.45M
{
505
1.45M
    os_ptr op = osp;
506
507
1.45M
    check_op(1);
508
1.45M
    check_proc(*op);
509
1.45M
    check_estack(4);
510
    /* Push a mark and the procedure, and invoke */
511
    /* the continuation operator. */
512
1.45M
    push_mark_estack(es_for, no_cleanup);
513
1.45M
    *++esp = *op;
514
1.45M
    make_op_estack(esp + 1, loop_continue);
515
1.45M
    pop(1);
516
1.45M
    return loop_continue(i_ctx_p);
517
1.45M
}
518
/* Continuation operator for loop */
519
static int
520
loop_continue(i_ctx_t *i_ctx_p)
521
4.73M
{
522
4.73M
    register es_ptr ep = esp; /* saved proc */
523
524
4.73M
    ref_assign(ep + 2, ep);
525
4.73M
    esp = ep + 2;
526
4.73M
    return o_push_estack;
527
4.73M
}
528
529
/* - exit - */
530
static int
531
zexit(i_ctx_t *i_ctx_p)
532
1.46M
{
533
1.46M
    os_ptr op = osp;
534
1.46M
    ref_stack_enum_t rsenum;
535
1.46M
    uint scanned = 0;
536
537
1.46M
    ref_stack_enum_begin(&rsenum, &e_stack);
538
1.46M
    do {
539
1.46M
        uint used = rsenum.size;
540
1.46M
        es_ptr ep = rsenum.ptr + used - 1;
541
1.46M
        uint count = used;
542
543
5.86M
        for (; count; count--, ep--)
544
5.86M
            if (r_is_estack_mark(ep))
545
1.46M
                switch (estack_mark_index(ep)) {
546
1.46M
                    case es_for:
547
1.46M
                        pop_estack(i_ctx_p, scanned + (used - count + 1));
548
1.46M
                        return o_pop_estack;
549
1
                    case es_stopped:
550
1
                        return_error(gs_error_invalidexit); /* not a loop */
551
1.46M
                }
552
0
        scanned += used;
553
0
    } while (ref_stack_enum_next(&rsenum));
554
    /* No mark, quit.  (per Adobe documentation) */
555
1.46M
    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
1.55M
{
572
1.55M
    os_ptr op = osp;
573
574
1.55M
    push(1);
575
1.55M
    *op = esp[-1];
576
1.55M
    esp -= 3;
577
1.55M
    return o_pop_estack;
578
1.55M
}
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
7.39M
{
587
7.39M
    os_ptr op = osp;
588
7.39M
    uint count = count_to_stopped(i_ctx_p, 1L);
589
590
7.39M
    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
7.39M
        check_ostack(2);
597
7.39M
        pop_estack(i_ctx_p, count);
598
7.39M
        op = osp;
599
7.39M
        push(1);
600
7.39M
        make_true(op);
601
7.39M
        return o_pop_estack;
602
7.39M
    }
603
    /* No mark, quit.  (per Adobe documentation) */
604
7.39M
    push(2);
605
0
    return unmatched_exit(op, zstop);
606
0
}
607
608
/* <result> <mask> .stop - */
609
static int
610
zzstop(i_ctx_t *i_ctx_p)
611
0
{
612
0
    os_ptr op = osp;
613
0
    uint count;
614
615
0
    check_op(2);
616
0
    check_type(*op, t_integer);
617
0
    count = count_to_stopped(i_ctx_p, op->value.intval);
618
0
    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
0
        ref save_result;
625
626
0
        check_op(2);
627
0
        save_result = op[-1];
628
0
        pop(2);
629
0
        pop_estack(i_ctx_p, count);
630
0
        op = osp;
631
0
        push(1);
632
0
        *op = save_result;
633
0
        return o_pop_estack;
634
0
    }
635
    /* No mark, quit.  (per Adobe documentation) */
636
0
    return unmatched_exit(op, zzstop);
637
0
}
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
727k
{
646
727k
    os_ptr op = osp;
647
648
727k
    check_op(1);
649
    /* Mark the execution stack, and push the default result */
650
    /* in case control returns normally. */
651
727k
    check_estack(5);
652
727k
    push_mark_estack(es_stopped, no_cleanup);
653
727k
    ++esp;
654
727k
    make_false(esp);    /* save the result */
655
727k
    ++esp;
656
727k
    make_int(esp, 1);   /* save the signal mask */
657
727k
    push_op_estack(stopped_push);
658
727k
    push_op_estack(zexec);  /* execute the operand */
659
727k
    return o_push_estack;
660
727k
}
661
662
/* <obj> <result> <mask> .stopped <result> */
663
static int
664
zzstopped(i_ctx_t *i_ctx_p)
665
8.27M
{
666
8.27M
    os_ptr op = osp;
667
8.27M
    check_type(*op, t_integer);
668
8.27M
    check_op(3);
669
    /* Mark the execution stack, and push the default result */
670
    /* in case control returns normally. */
671
8.27M
    check_estack(5);
672
8.27M
    push_mark_estack(es_stopped, no_cleanup);
673
8.27M
    *++esp = op[-1];    /* save the result */
674
8.27M
    *++esp = *op;   /* save the signal mask */
675
8.27M
    push_op_estack(stopped_push);
676
8.27M
    push_op_estack(zexec);  /* execute the operand */
677
8.27M
    pop(2);
678
8.27M
    return o_push_estack;
679
8.27M
}
680
681
/* <mask> .instopped false */
682
/* <mask> .instopped <result> true */
683
static int
684
zinstopped(i_ctx_t *i_ctx_p)
685
7.39M
{
686
7.39M
    os_ptr op = osp;
687
7.39M
    uint count;
688
689
7.39M
    check_type(*op, t_integer);
690
7.39M
    count = count_to_stopped(i_ctx_p, op->value.intval);
691
7.39M
    if (count) {
692
7.39M
        push(1);
693
7.39M
        op[-1] = *ref_stack_index(&e_stack, count - 2);   /* default result */
694
7.39M
        make_true(op);
695
7.39M
    } else
696
7.39M
        make_false(op);
697
7.39M
    return 0;
698
7.39M
}
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
21.6k
{
706
21.6k
    os_ptr op = osp;
707
708
21.6k
    push(1);
709
21.6k
    make_int(op, count_exec_stack(i_ctx_p, false));
710
21.6k
    return 0;
711
21.6k
}
712
static int
713
zcountexecstack1(i_ctx_t *i_ctx_p)
714
1.34k
{
715
1.34k
    os_ptr op = osp;
716
717
1.34k
    check_type(*op, t_boolean);
718
1.34k
    make_int(op, count_exec_stack(i_ctx_p, op->value.boolval));
719
1.34k
    return 0;
720
1.34k
}
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
22.9k
{
731
22.9k
    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
22.9k
    uint depth;
740
741
22.9k
    if (!r_is_array(op1))
742
22.9k
        return_op_typecheck(op1);
743
    /* Check the length before the write access per CET 28-03 */
744
22.9k
    size = r_size(op1);
745
22.9k
    depth = count_exec_stack(i_ctx_p, include_marks);
746
22.9k
    if (depth > size)
747
0
        return_error(gs_error_rangecheck);
748
22.9k
    check_write(*op1);
749
22.9k
    {
750
22.9k
        int code = ref_stack_store_check(&e_stack, op1, size, 0);
751
752
22.9k
        if (code < 0)
753
0
            return code;
754
22.9k
    }
755
22.9k
    check_estack(1);
756
22.9k
    r_set_size(op1, depth);
757
22.9k
    push_op_estack(cont);
758
22.9k
    return o_push_estack;
759
22.9k
}
760
static int
761
zexecstack(i_ctx_t *i_ctx_p)
762
21.6k
{
763
21.6k
    os_ptr op = osp;
764
765
21.6k
    return push_execstack(i_ctx_p, op, false, execstack_continue);
766
21.6k
}
767
static int
768
zexecstack2(i_ctx_t *i_ctx_p)
769
1.34k
{
770
1.34k
    os_ptr op = osp;
771
772
1.34k
    check_type(*op, t_boolean);
773
1.34k
    return push_execstack(i_ctx_p, op - 1, op->value.boolval, execstack2_continue);
774
1.34k
}
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
22.9k
{
780
22.9k
    os_ptr op = osp;
781
22.9k
    ref *arefs = op1->value.refs;
782
22.9k
    uint asize = r_size(op1);
783
22.9k
    uint i;
784
22.9k
    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
2.13M
    for (i = 0, rq = arefs + asize; rq != arefs; ++i) {
795
2.10M
        const ref *rp = ref_stack_index(&e_stack, (long)i);
796
797
2.10M
        if (rp == NULL)
798
0
            continue;
799
2.10M
        if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks)
800
353k
            continue;
801
1.75M
        --rq;
802
1.75M
        ref_assign_old(op1, rq, rp, "execstack");
803
1.75M
        switch (r_type(rq)) {
804
378k
            case t_operator: {
805
378k
                uint opidx = op_index(rq);
806
807
378k
                if (opidx == 0 || op_def_is_internal(op_index_def(opidx)))
808
378k
                    r_clear_attrs(rq, a_executable);
809
378k
                break;
810
0
            }
811
2.19k
            case t_struct:
812
2.19k
            case t_astruct: {
813
2.19k
                const char *tname = rq->value.pstruct ?
814
2.19k
                    gs_struct_type_name_string(
815
2.19k
                                gs_object_type(imemory, rq->value.pstruct))
816
2.19k
                    : "NULL";
817
818
2.19k
                make_const_string(rq, a_readonly | avm_foreign,
819
2.19k
                                  strlen(tname), (const byte *)tname);
820
2.19k
                break;
821
2.19k
            }
822
29.3k
            case t_array:
823
46.8k
            case t_shortarray:
824
440k
            case t_mixedarray:
825
440k
                if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0)
826
440k
                    make_null(rq);
827
440k
                break;
828
933k
            default:
829
933k
                ;
830
1.75M
        }
831
1.75M
    }
832
22.9k
    pop(op - op1);
833
22.9k
    return 0;
834
22.9k
}
835
static int
836
execstack_continue(i_ctx_t *i_ctx_p)
837
21.6k
{
838
21.6k
    os_ptr op = osp;
839
840
21.6k
    return do_execstack(i_ctx_p, false, false, op);
841
21.6k
}
842
static int
843
execstack2_continue(i_ctx_t *i_ctx_p)
844
1.34k
{
845
1.34k
    os_ptr op = osp;
846
847
1.34k
    return do_execstack(i_ctx_p, op->value.boolval, true, op - 1);
848
1.34k
}
849
850
/* - .needinput - */
851
static int
852
zneedinput(i_ctx_t *i_ctx_p)
853
119k
{
854
119k
    return gs_error_NeedInput;    /* interpreter will exit to caller */
855
119k
}
856
857
/* <obj> <int> .quit - */
858
static int
859
zquit(i_ctx_t *i_ctx_p)
860
46.4k
{
861
46.4k
    os_ptr op = osp;
862
863
46.4k
    check_op(2);
864
46.4k
    check_type(*op, t_integer);
865
46.4k
    return_error(gs_error_Quit);  /* Interpreter will do the exit */
866
46.4k
}
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
39.5k
{
872
39.5k
    ref_stack_enum_t rsenum;
873
874
39.5k
    ref_stack_enum_begin(&rsenum, &e_stack);
875
39.5k
    do {
876
39.5k
        uint count = rsenum.size;
877
39.5k
        es_ptr ep = rsenum.ptr + count - 1;
878
879
1.84M
        for (; count; count--, ep--)
880
1.84M
            if (r_has_type_attrs(ep, t_file, a_executable))
881
39.5k
                return ep;
882
39.5k
    } while (ref_stack_enum_next(&rsenum));
883
0
    return 0;
884
39.5k
}
885
886
/* - currentfile <file> */
887
int
888
z_current_file(i_ctx_t *i_ctx_p, ref **s)
889
1.26M
{
890
1.26M
    ref *fp;
891
    /* Check the cache first */
892
1.26M
    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
1.22M
            *s = esfile;
904
1.22M
    } else if ((fp = zget_current_file(i_ctx_p)) == 0) { /* Return an invalid file object. */
905
0
        *s = NULL;
906
39.5k
    } else {
907
39.5k
        *s = fp;
908
39.5k
        esfile_set_cache(fp);
909
39.5k
    }
910
1.26M
    return 0;
911
1.26M
}
912
static int
913
zcurrentfile(i_ctx_t *i_ctx_p)
914
1.26M
{
915
1.26M
    os_ptr op = osp;
916
1.26M
    ref *s;
917
1.26M
    int code;
918
919
1.26M
    push(1);
920
921
1.26M
    code = z_current_file(i_ctx_p, &s);
922
1.26M
    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
1.26M
    else {
928
1.26M
        ref_assign(op, s);
929
1.26M
    }
930
    /* Make the returned value literal. */
931
1.26M
    r_clear_attrs(op, a_executable);
932
1.26M
    return code;
933
1.26M
}
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
138M
{
996
138M
    if (!r_has_attr(op, a_execute) && /* only true if noaccess */
997
138M
        ref_type_uses_access(r_type(op)) &&
998
138M
        (r_has_attr(op, a_executable) || !r_has_type(op, t_dictionary))
999
138M
        ) {
1000
0
        return_error(gs_error_invalidaccess);
1001
0
    }
1002
138M
    return 0;
1003
138M
}
1004
1005
/* Vacuous cleanup routine */
1006
static int
1007
no_cleanup(i_ctx_t *i_ctx_p)
1008
8.86M
{
1009
8.86M
    return 0;
1010
8.86M
}
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
45.9k
{
1019
45.9k
    uint count = ref_stack_count(&e_stack);
1020
1021
45.9k
    if (!include_marks) {
1022
45.9k
        uint i;
1023
1024
4.26M
        for (i = count; i--;) {
1025
4.21M
            ref *o;
1026
4.21M
            o = ref_stack_index(&e_stack, (long)i);
1027
4.21M
            if (o == NULL)
1028
0
                continue;
1029
4.21M
            if (r_has_type_attrs(o, t_null, a_executable))
1030
706k
                --count;
1031
4.21M
        }
1032
45.9k
    }
1033
45.9k
    return count;
1034
45.9k
}
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
14.7M
{
1044
14.7M
    ref_stack_enum_t rsenum;
1045
14.7M
    uint scanned = 0;
1046
1047
14.7M
    ref_stack_enum_begin(&rsenum, &e_stack);
1048
14.7M
    do {
1049
14.7M
        uint used = rsenum.size;
1050
14.7M
        es_ptr ep = rsenum.ptr + used - 1;
1051
14.7M
        uint count = used;
1052
1053
155M
        for (; count; count--, ep--) {
1054
155M
            if (r_is_estack_mark(ep)) {
1055
28.9M
                if (estack_mark_index(ep) == es_stopped &&
1056
28.9M
                  (ep[2].value.intval & mask) != 0)
1057
14.7M
                    return scanned + (used - count + 1);
1058
28.9M
            }
1059
155M
        }
1060
0
        scanned += used;
1061
0
    } while (ref_stack_enum_next(&rsenum));
1062
0
    return 0;
1063
14.7M
}
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
8.86M
{
1073
8.86M
    uint idx = 0;
1074
8.86M
    uint popped = 0;
1075
1076
8.86M
    esfile_clear_cache();
1077
92.3M
    for (; idx < count; idx++) {
1078
83.4M
        ref *ep = ref_stack_index(&e_stack, idx - popped);
1079
1080
83.4M
        if (ep == NULL)
1081
0
            continue;
1082
1083
83.4M
        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
15.9M
            op_proc_t opproc = real_opproc(ep);
1094
15.9M
            ref_stack_pop(&e_stack, idx - popped);
1095
15.9M
            esp--;
1096
15.9M
            (*opproc) (i_ctx_p);
1097
15.9M
            esp++;
1098
15.9M
            ref_stack_pop(&e_stack, 1);
1099
15.9M
            popped = idx + 1;
1100
15.9M
        }
1101
83.4M
    }
1102
8.86M
    ref_stack_pop(&e_stack, count - popped);
1103
8.86M
}
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
0
{
1113
0
    make_oper(op - 1, 0, opproc);
1114
0
    make_int(op, gs_error_invalidexit);
1115
0
    return_error(gs_error_Quit);
1116
0
}