Coverage Report

Created: 2022-04-16 11:23

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