Coverage Report

Created: 2025-06-10 06:56

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