Coverage Report

Created: 2022-10-31 07:00

/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
1.12G
{
105
1.12G
    os_ptr op = osp;
106
1.12G
    int code;
107
108
1.12G
    check_op(1);
109
1.12G
    code = check_for_exec(op);
110
1.12G
    if (code < 0) {
111
0
        return code;
112
0
    }
113
1.12G
    if (!r_has_attr(op, a_executable)) {
114
5.53M
        return 0; /* shortcut, literal object just gets pushed back */
115
5.53M
    }
116
1.12G
    check_estack(1);
117
1.12G
    ++esp;
118
1.12G
    ref_assign(esp, op);
119
1.12G
    esfile_check_cache();
120
1.12G
    pop(1);
121
1.12G
    return o_push_estack;
122
1.12G
}
123
124
/* <obj1> ... <objn> <n> .execn - */
125
static int
126
zexecn(i_ctx_t *i_ctx_p)
127
2.39M
{
128
2.39M
    os_ptr op = osp;
129
2.39M
    uint n, i;
130
2.39M
    es_ptr esp_orig;
131
132
2.39M
    check_int_leu(*op, max_uint - 1);
133
2.39M
    n = (uint) op->value.intval;
134
2.39M
    check_op(n + 1);
135
2.39M
    check_estack(n);
136
2.39M
    esp_orig = esp;
137
9.12M
    for (i = 0; i < n; ++i) {
138
6.72M
        const ref *rp = ref_stack_index(&o_stack, (long)(i + 1));
139
140
        /* Make sure this object is legal to execute. */
141
6.72M
        if (ref_type_uses_access(r_type(rp))) {
142
3.10M
            if (!r_has_attr(rp, a_execute) &&
143
3.10M
                r_has_attr(rp, a_executable)
144
3.10M
                ) {
145
0
                esp = esp_orig;
146
0
                return_error(gs_error_invalidaccess);
147
0
            }
148
3.10M
        }
149
        /* Executable nulls have a special meaning on the e-stack, */
150
        /* so since they are no-ops, don't push them. */
151
6.72M
        if (!r_has_type_attrs(rp, t_null, a_executable)) {
152
6.72M
            ++esp;
153
6.72M
            ref_assign(esp, rp);
154
6.72M
        }
155
6.72M
    }
156
2.39M
    esfile_check_cache();
157
2.39M
    pop(n + 1);
158
2.39M
    return o_push_estack;
159
2.39M
}
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
15.5M
{
281
15.5M
    os_ptr op = osp;
282
15.5M
    register es_ptr ep;
283
15.5M
    int code;
284
15.5M
    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
15.5M
    if ((code = float_params(op - 1, 3, params)) < 0)
290
48
        return code;
291
15.5M
    if ( params[0] == 0.0 && params[1] == 0.0 ) {
292
22
        pop(4);    /* don't run the proc */
293
22
        return 0;
294
22
    }
295
15.5M
    check_estack(7);
296
15.5M
    ep = esp + 6;
297
15.5M
    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
15.5M
    if (r_has_type(op - 3, t_integer) &&
302
15.5M
        r_has_type(op - 2, t_integer)
303
15.5M
        ) {
304
15.5M
        make_int(ep - 4, op[-3].value.intval);
305
15.5M
        make_int(ep - 3, op[-2].value.intval);
306
15.5M
        switch (r_type(op - 1)) {
307
15.5M
            case t_integer:
308
15.5M
                make_int(ep - 2, op[-1].value.intval);
309
15.5M
                break;
310
1
            case t_real:
311
1
                make_int(ep - 2, (ps_int)op[-1].value.realval);
312
1
                break;
313
0
            default:
314
0
                return_op_typecheck(op - 1);
315
15.5M
        }
316
15.5M
        if (ep[-3].value.intval >= 0)
317
15.5M
            make_op_estack(ep, for_pos_int_continue);
318
11.9M
        else
319
15.5M
            make_op_estack(ep, for_neg_int_continue);
320
15.5M
    } else {
321
3
        make_real(ep - 4, params[0]);
322
3
        make_real(ep - 3, params[1]);
323
3
        make_real(ep - 2, params[2]);
324
3
        make_op_estack(ep, for_real_continue);
325
3
    }
326
15.5M
    make_mark_estack(ep - 5, es_for, no_cleanup);
327
15.5M
    ref_assign(ep - 1, op);
328
15.5M
    esp = ep;
329
15.5M
    pop(4);
330
15.5M
    return o_push_estack;
331
15.5M
}
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
174M
{
340
174M
    os_ptr op = osp;
341
174M
    register es_ptr ep = esp;
342
174M
    ps_int var = ep[-3].value.intval;
343
344
174M
    if (var > ep[-1].value.intval) {
345
3.65M
        esp -= 5;    /* pop everything */
346
3.65M
        return o_pop_estack;
347
3.65M
    }
348
174M
    push(1);
349
171M
    make_int(op, var);
350
171M
    ep[-3].value.intval = var + ep[-2].value.intval;
351
171M
    ref_assign_inline(ep + 2, ep); /* saved proc */
352
171M
    esp = ep + 2;
353
171M
    return o_push_estack;
354
171M
}
355
/* Continuation operator for negative integers. */
356
static int
357
for_neg_int_continue(i_ctx_t *i_ctx_p)
358
93.8M
{
359
93.8M
    os_ptr op = osp;
360
93.8M
    register es_ptr ep = esp;
361
93.8M
    ps_int var = ep[-3].value.intval;
362
363
93.8M
    if (var < ep[-1].value.intval) {
364
11.9M
        esp -= 5;    /* pop everything */
365
11.9M
        return o_pop_estack;
366
11.9M
    }
367
93.8M
    push(1);
368
81.9M
    make_int(op, var);
369
81.9M
    ep[-3].value.intval = var + ep[-2].value.intval;
370
81.9M
    ref_assign(ep + 2, ep); /* saved proc */
371
81.9M
    esp = ep + 2;
372
81.9M
    return o_push_estack;
373
81.9M
}
374
/* Continuation operator for reals. */
375
static int
376
for_real_continue(i_ctx_t *i_ctx_p)
377
3
{
378
3
    os_ptr op = osp;
379
3
    es_ptr ep = esp;
380
3
    float var = ep[-3].value.realval;
381
3
    float incr = ep[-2].value.realval;
382
383
3
    if (incr >= 0 ? (var > ep[-1].value.realval) :
384
3
        (var < ep[-1].value.realval)
385
3
        ) {
386
1
        esp -= 5;    /* pop everything */
387
1
        return o_pop_estack;
388
1
    }
389
3
    push(1);
390
2
    ref_assign(op, ep - 3);
391
2
    ep[-3].value.realval = var + incr;
392
2
    esp = ep + 2;
393
2
    ref_assign(ep + 2, ep); /* saved proc */
394
2
    return o_push_estack;
395
2
}
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
205k
{
410
205k
    os_ptr op = osp;
411
205k
    es_ptr ep;
412
413
205k
    check_type(op[-3], t_real);
414
205k
    check_type(op[-2], t_integer);
415
205k
    check_type(op[-1], t_real);
416
205k
    check_proc(*op);
417
205k
    check_estack(8);
418
205k
    ep = esp + 7;
419
205k
    make_mark_estack(ep - 6, es_for, no_cleanup);
420
205k
    make_int(ep - 5, 0);
421
205k
    memcpy(ep - 4, op - 3, 3 * sizeof(ref));
422
205k
    ref_assign(ep - 1, op);
423
205k
    make_op_estack(ep, for_samples_continue);
424
205k
    esp = ep;
425
205k
    pop(4);
426
205k
    return o_push_estack;
427
205k
}
428
/* Continuation procedure */
429
static int
430
for_samples_continue(i_ctx_t *i_ctx_p)
431
52.7M
{
432
52.7M
    os_ptr op = osp;
433
52.7M
    es_ptr ep = esp;
434
52.7M
    int var = ep[-4].value.intval;
435
52.7M
    float a = ep[-3].value.realval;
436
52.7M
    int n = ep[-2].value.intval;
437
52.7M
    float b = ep[-1].value.realval;
438
439
52.7M
    if (var > n) {
440
205k
        esp -= 6;    /* pop everything */
441
205k
        return o_pop_estack;
442
205k
    }
443
52.7M
    push(1);
444
52.5M
    make_real(op, ((n - var) * a + var * b) / n);
445
52.5M
    ep[-4].value.intval = var + 1;
446
52.5M
    ref_assign_inline(ep + 2, ep); /* saved proc */
447
52.5M
    esp = ep + 2;
448
52.5M
    return o_push_estack;
449
52.5M
}
450
451
/* <int> <proc> repeat - */
452
static int repeat_continue(i_ctx_t *);
453
int
454
zrepeat(i_ctx_t *i_ctx_p)
455
4.72M
{
456
4.72M
    os_ptr op = osp;
457
4.72M
    check_proc(*op);
458
4.72M
    check_type(op[-1], t_integer);
459
4.72M
    if (op[-1].value.intval < 0)
460
0
        return_error(gs_error_rangecheck);
461
4.72M
    check_estack(5);
462
    /* Push a mark, the count, and the procedure, and invoke */
463
    /* the continuation operator. */
464
4.72M
    push_mark_estack(es_for, no_cleanup);
465
4.72M
    *++esp = op[-1];
466
4.72M
    *++esp = *op;
467
4.72M
    make_op_estack(esp + 1, repeat_continue);
468
4.72M
    pop(2);
469
4.72M
    return repeat_continue(i_ctx_p);
470
4.72M
}
471
/* Continuation operator for repeat */
472
static int
473
repeat_continue(i_ctx_t *i_ctx_p)
474
172M
{
475
172M
    es_ptr ep = esp;   /* saved proc */
476
477
172M
    if (--(ep[-1].value.intval) >= 0) {   /* continue */
478
167M
        esp += 2;
479
167M
        ref_assign(esp, ep);
480
167M
        return o_push_estack;
481
167M
    } else {     /* done */
482
4.72M
        esp -= 3;    /* pop mark, count, proc */
483
4.72M
        return o_pop_estack;
484
4.72M
    }
485
172M
}
486
487
/* <proc> loop */
488
static int loop_continue(i_ctx_t *);
489
static int
490
zloop(i_ctx_t *i_ctx_p)
491
11.8M
{
492
11.8M
    os_ptr op = osp;
493
494
11.8M
    check_proc(*op);
495
11.8M
    check_estack(4);
496
    /* Push a mark and the procedure, and invoke */
497
    /* the continuation operator. */
498
11.8M
    push_mark_estack(es_for, no_cleanup);
499
11.8M
    *++esp = *op;
500
11.8M
    make_op_estack(esp + 1, loop_continue);
501
11.8M
    pop(1);
502
11.8M
    return loop_continue(i_ctx_p);
503
11.8M
}
504
/* Continuation operator for loop */
505
static int
506
loop_continue(i_ctx_t *i_ctx_p)
507
181M
{
508
181M
    register es_ptr ep = esp; /* saved proc */
509
510
181M
    ref_assign(ep + 2, ep);
511
181M
    esp = ep + 2;
512
181M
    return o_push_estack;
513
181M
}
514
515
/* - exit - */
516
static int
517
zexit(i_ctx_t *i_ctx_p)
518
12.0M
{
519
12.0M
    os_ptr op = osp;
520
12.0M
    ref_stack_enum_t rsenum;
521
12.0M
    uint scanned = 0;
522
523
12.0M
    ref_stack_enum_begin(&rsenum, &e_stack);
524
12.0M
    do {
525
12.0M
        uint used = rsenum.size;
526
12.0M
        es_ptr ep = rsenum.ptr + used - 1;
527
12.0M
        uint count = used;
528
529
48.0M
        for (; count; count--, ep--)
530
48.0M
            if (r_is_estack_mark(ep))
531
12.0M
                switch (estack_mark_index(ep)) {
532
12.0M
                    case es_for:
533
12.0M
                        pop_estack(i_ctx_p, scanned + (used - count + 1));
534
12.0M
                        return o_pop_estack;
535
16
                    case es_stopped:
536
16
                        return_error(gs_error_invalidexit); /* not a loop */
537
12.0M
                }
538
0
        scanned += used;
539
0
    } while (ref_stack_enum_next(&rsenum));
540
    /* No mark, quit.  (per Adobe documentation) */
541
12.0M
    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
22.4M
{
558
22.4M
    os_ptr op = osp;
559
560
22.4M
    push(1);
561
22.4M
    *op = esp[-1];
562
22.4M
    esp -= 3;
563
22.4M
    return o_pop_estack;
564
22.4M
}
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
48.8M
{
573
48.8M
    os_ptr op = osp;
574
48.8M
    uint count = count_to_stopped(i_ctx_p, 1L);
575
576
48.8M
    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
48.8M
        check_ostack(2);
583
48.8M
        pop_estack(i_ctx_p, count);
584
48.8M
        op = osp;
585
48.8M
        push(1);
586
48.8M
        make_true(op);
587
48.8M
        return o_pop_estack;
588
48.8M
    }
589
    /* No mark, quit.  (per Adobe documentation) */
590
48.8M
    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
4.28M
{
631
4.28M
    os_ptr op = osp;
632
633
4.28M
    check_op(1);
634
    /* Mark the execution stack, and push the default result */
635
    /* in case control returns normally. */
636
4.28M
    check_estack(5);
637
4.28M
    push_mark_estack(es_stopped, no_cleanup);
638
4.28M
    ++esp;
639
4.28M
    make_false(esp);    /* save the result */
640
4.28M
    ++esp;
641
4.28M
    make_int(esp, 1);   /* save the signal mask */
642
4.28M
    push_op_estack(stopped_push);
643
4.28M
    push_op_estack(zexec);  /* execute the operand */
644
4.28M
    return o_push_estack;
645
4.28M
}
646
647
/* <obj> <result> <mask> .stopped <result> */
648
static int
649
zzstopped(i_ctx_t *i_ctx_p)
650
67.2M
{
651
67.2M
    os_ptr op = osp;
652
67.2M
    check_type(*op, t_integer);
653
67.2M
    check_op(3);
654
    /* Mark the execution stack, and push the default result */
655
    /* in case control returns normally. */
656
67.2M
    check_estack(5);
657
67.2M
    push_mark_estack(es_stopped, no_cleanup);
658
67.2M
    *++esp = op[-1];    /* save the result */
659
67.2M
    *++esp = *op;   /* save the signal mask */
660
67.2M
    push_op_estack(stopped_push);
661
67.2M
    push_op_estack(zexec);  /* execute the operand */
662
67.2M
    pop(2);
663
67.2M
    return o_push_estack;
664
67.2M
}
665
666
/* <mask> .instopped false */
667
/* <mask> .instopped <result> true */
668
static int
669
zinstopped(i_ctx_t *i_ctx_p)
670
48.7M
{
671
48.7M
    os_ptr op = osp;
672
48.7M
    uint count;
673
674
48.7M
    check_type(*op, t_integer);
675
48.7M
    count = count_to_stopped(i_ctx_p, op->value.intval);
676
48.7M
    if (count) {
677
48.7M
        push(1);
678
48.7M
        op[-1] = *ref_stack_index(&e_stack, count - 2);   /* default result */
679
48.7M
        make_true(op);
680
48.7M
    } else
681
48.7M
        make_false(op);
682
48.7M
    return 0;
683
48.7M
}
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
137k
{
691
137k
    os_ptr op = osp;
692
693
137k
    push(1);
694
137k
    make_int(op, count_exec_stack(i_ctx_p, false));
695
137k
    return 0;
696
137k
}
697
static int
698
zcountexecstack1(i_ctx_t *i_ctx_p)
699
7.52k
{
700
7.52k
    os_ptr op = osp;
701
702
7.52k
    check_type(*op, t_boolean);
703
7.52k
    make_int(op, count_exec_stack(i_ctx_p, op->value.boolval));
704
7.52k
    return 0;
705
7.52k
}
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
145k
{
716
145k
    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
145k
    uint depth;
725
726
145k
    if (!r_is_array(op1))
727
145k
        return_op_typecheck(op1);
728
    /* Check the length before the write access per CET 28-03 */
729
145k
    size = r_size(op1);
730
145k
    depth = count_exec_stack(i_ctx_p, include_marks);
731
145k
    if (depth > size)
732
0
        return_error(gs_error_rangecheck);
733
145k
    check_write(*op1);
734
145k
    {
735
145k
        int code = ref_stack_store_check(&e_stack, op1, size, 0);
736
737
145k
        if (code < 0)
738
0
            return code;
739
145k
    }
740
145k
    check_estack(1);
741
145k
    r_set_size(op1, depth);
742
145k
    push_op_estack(cont);
743
145k
    return o_push_estack;
744
145k
}
745
static int
746
zexecstack(i_ctx_t *i_ctx_p)
747
137k
{
748
137k
    os_ptr op = osp;
749
750
137k
    return push_execstack(i_ctx_p, op, false, execstack_continue);
751
137k
}
752
static int
753
zexecstack2(i_ctx_t *i_ctx_p)
754
7.52k
{
755
7.52k
    os_ptr op = osp;
756
757
7.52k
    check_type(*op, t_boolean);
758
7.52k
    return push_execstack(i_ctx_p, op - 1, op->value.boolval, execstack2_continue);
759
7.52k
}
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
145k
{
765
145k
    os_ptr op = osp;
766
145k
    ref *arefs = op1->value.refs;
767
145k
    uint asize = r_size(op1);
768
145k
    uint i;
769
145k
    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
11.9M
    for (i = 0, rq = arefs + asize; rq != arefs; ++i) {
780
11.7M
        const ref *rp = ref_stack_index(&e_stack, (long)i);
781
782
11.7M
        if (r_has_type_attrs(rp, t_null, a_executable) && !include_marks)
783
1.96M
            continue;
784
9.81M
        --rq;
785
9.81M
        ref_assign_old(op1, rq, rp, "execstack");
786
9.81M
        switch (r_type(rq)) {
787
2.11M
            case t_operator: {
788
2.11M
                uint opidx = op_index(rq);
789
790
2.11M
                if (opidx == 0 || op_def_is_internal(op_index_def(opidx)))
791
2.11M
                    r_clear_attrs(rq, a_executable);
792
2.11M
                break;
793
0
            }
794
108
            case t_struct:
795
108
            case t_astruct: {
796
108
                const char *tname = rq->value.pstruct ?
797
108
                    gs_struct_type_name_string(
798
108
                                gs_object_type(imemory, rq->value.pstruct))
799
108
                    : "NULL";
800
801
108
                make_const_string(rq, a_readonly | avm_foreign,
802
108
                                  strlen(tname), (const byte *)tname);
803
108
                break;
804
108
            }
805
106k
            case t_array:
806
327k
            case t_shortarray:
807
2.39M
            case t_mixedarray:
808
2.39M
                if (!include_oparrays && errorexec_find(i_ctx_p, rq) < 0)
809
2.39M
                    make_null(rq);
810
2.39M
                break;
811
5.30M
            default:
812
5.30M
                ;
813
9.81M
        }
814
9.81M
    }
815
145k
    pop(op - op1);
816
145k
    return 0;
817
145k
}
818
static int
819
execstack_continue(i_ctx_t *i_ctx_p)
820
137k
{
821
137k
    os_ptr op = osp;
822
823
137k
    return do_execstack(i_ctx_p, false, false, op);
824
137k
}
825
static int
826
execstack2_continue(i_ctx_t *i_ctx_p)
827
7.52k
{
828
7.52k
    os_ptr op = osp;
829
830
7.52k
    return do_execstack(i_ctx_p, op->value.boolval, true, op - 1);
831
7.52k
}
832
833
/* - .needinput - */
834
static int
835
zneedinput(i_ctx_t *i_ctx_p)
836
803k
{
837
803k
    return gs_error_NeedInput;    /* interpreter will exit to caller */
838
803k
}
839
840
/* <obj> <int> .quit - */
841
static int
842
zquit(i_ctx_t *i_ctx_p)
843
302k
{
844
302k
    os_ptr op = osp;
845
846
302k
    check_op(2);
847
302k
    check_type(*op, t_integer);
848
302k
    return_error(gs_error_Quit);  /* Interpreter will do the exit */
849
302k
}
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
131M
{
856
131M
    os_ptr op = osp;
857
131M
    ref *fp;
858
859
131M
    push(1);
860
    /* Check the cache first */
861
131M
    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
131M
            ref_assign(op, esfile);
873
131M
    } 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
219k
    } else {
878
219k
        ref_assign(op, fp);
879
219k
        esfile_set_cache(fp);
880
219k
    }
881
    /* Make the returned value literal. */
882
131M
    r_clear_attrs(op, a_executable);
883
131M
    return 0;
884
131M
}
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
219k
{
889
219k
    ref_stack_enum_t rsenum;
890
891
219k
    ref_stack_enum_begin(&rsenum, &e_stack);
892
219k
    do {
893
219k
        uint count = rsenum.size;
894
219k
        es_ptr ep = rsenum.ptr + count - 1;
895
896
9.87M
        for (; count; count--, ep--)
897
9.87M
            if (r_has_type_attrs(ep, t_file, a_executable))
898
219k
                return ep;
899
219k
    } while (ref_stack_enum_next(&rsenum));
900
0
    return 0;
901
219k
}
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
1.12G
{
965
1.12G
    if (!r_has_attr(op, a_execute) && /* only true if noaccess */
966
1.12G
        ref_type_uses_access(r_type(op)) &&
967
1.12G
        (r_has_attr(op, a_executable) || !r_has_type(op, t_dictionary))
968
1.12G
        ) {
969
0
        return_error(gs_error_invalidaccess);
970
0
    }
971
1.12G
    return 0;
972
1.12G
}
973
974
/* Vacuous cleanup routine */
975
static int
976
no_cleanup(i_ctx_t *i_ctx_p)
977
60.6M
{
978
60.6M
    return 0;
979
60.6M
}
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
290k
{
988
290k
    uint count = ref_stack_count(&e_stack);
989
990
290k
    if (!include_marks) {
991
290k
        uint i;
992
993
23.8M
        for (i = count; i--;)
994
23.5M
            if (r_has_type_attrs(ref_stack_index(&e_stack, (long)i),
995
23.5M
                                 t_null, a_executable))
996
3.93M
                --count;
997
290k
    }
998
290k
    return count;
999
290k
}
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
97.5M
{
1009
97.5M
    ref_stack_enum_t rsenum;
1010
97.5M
    uint scanned = 0;
1011
1012
97.5M
    ref_stack_enum_begin(&rsenum, &e_stack);
1013
97.5M
    do {
1014
97.5M
        uint used = rsenum.size;
1015
97.5M
        es_ptr ep = rsenum.ptr + used - 1;
1016
97.5M
        uint count = used;
1017
1018
1.04G
        for (; count; count--, ep--) {
1019
1.04G
            if (r_is_estack_mark(ep)) {
1020
190M
                if (estack_mark_index(ep) == es_stopped &&
1021
190M
                  (ep[2].value.intval & mask) != 0)
1022
97.5M
                    return scanned + (used - count + 1);
1023
190M
            }
1024
1.04G
        }
1025
56
        scanned += used;
1026
56
    } while (ref_stack_enum_next(&rsenum));
1027
56
    return 0;
1028
97.5M
}
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
60.8M
{
1038
60.8M
    uint idx = 0;
1039
60.8M
    uint popped = 0;
1040
1041
60.8M
    esfile_clear_cache();
1042
629M
    for (; idx < count; idx++) {
1043
568M
        ref *ep = ref_stack_index(&e_stack, idx - popped);
1044
1045
568M
        if (r_is_estack_mark(ep)) {
1046
107M
            ref_stack_pop(&e_stack, idx + 1 - popped);
1047
107M
            popped = idx + 1;
1048
107M
            (*real_opproc(ep)) (i_ctx_p);
1049
107M
        }
1050
568M
    }
1051
60.8M
    ref_stack_pop(&e_stack, count - popped);
1052
60.8M
}
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
}