Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/graphite/src/Code.cpp
Line
Count
Source
1
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2
// Copyright 2010, SIL International, All rights reserved.
3
4
// This class represents loaded graphite stack machine code.  It performs
5
// basic sanity checks, on the incoming code to prevent more obvious problems
6
// from crashing graphite.
7
// Author: Tim Eves
8
9
#include <cassert>
10
#include <cstddef>
11
#include <cstdlib>
12
#include <cstring>
13
#include "graphite2/Segment.h"
14
#include "inc/Code.h"
15
#include "inc/Face.h"
16
#include "inc/GlyphFace.h"
17
#include "inc/GlyphCache.h"
18
#include "inc/Machine.h"
19
#include "inc/Rule.h"
20
#include "inc/Silf.h"
21
22
#include <cstdio>
23
24
#ifdef NDEBUG
25
#ifdef __GNUC__
26
#pragma GCC diagnostic ignored "-Wunused-parameter"
27
#endif
28
#endif
29
30
31
using namespace graphite2;
32
using namespace vm;
33
34
namespace {
35
36
0
inline bool is_return(const instr i) {
37
0
    const opcode_t * opmap = Machine::getOpcodeTable();
38
0
    const instr pop_ret  = *opmap[POP_RET].impl,
39
0
                ret_zero = *opmap[RET_ZERO].impl,
40
0
                ret_true = *opmap[RET_TRUE].impl;
41
0
    return i == pop_ret || i == ret_zero || i == ret_true;
42
0
}
43
44
struct context
45
{
46
0
    context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false;}
47
    struct {
48
        uint8   changed:1,
49
                referenced:1;
50
    } flags;
51
    uint8       codeRef;
52
};
53
54
} // end namespace
55
56
57
class Machine::Code::decoder
58
{
59
public:
60
    struct limits;
61
    static const int NUMCONTEXTS = 256;
62
63
    decoder(limits & lims, Code &code, enum passtype pt) throw();
64
65
    bool        load(const byte * bc_begin, const byte * bc_end);
66
    void        apply_analysis(instr * const code, instr * code_end);
67
0
    byte        max_ref() { return _max_ref; }
68
0
    int         out_index() const { return _out_index; }
69
70
private:
71
    void        set_ref(int index) throw();
72
    void        set_noref(int index) throw();
73
    void        set_changed(int index) throw();
74
    opcode      fetch_opcode(const byte * bc);
75
    void        analyse_opcode(const opcode, const int8 * const dp) throw();
76
    bool        emit_opcode(opcode opc, const byte * & bc);
77
    bool        validate_opcode(const byte opc, const byte * const bc);
78
    bool        valid_upto(const uint16 limit, const uint16 x) const throw();
79
    bool        test_context() const throw();
80
    bool        test_ref(int8 index) const throw();
81
    bool        test_attr(attrCode attr) const throw();
82
0
    void        failure(const status_t s) const throw() { _code.failure(s); }
83
84
    Code              & _code;
85
    int                 _out_index;
86
    uint16              _out_length;
87
    instr             * _instr;
88
    byte              * _data;
89
    limits            & _max;
90
    enum passtype       _passtype;
91
    int                 _stack_depth;
92
    bool                _in_ctxt_item;
93
    int16               _slotref;
94
    context             _contexts[NUMCONTEXTS];
95
    byte                _max_ref;
96
};
97
98
99
struct Machine::Code::decoder::limits
100
{
101
  const byte       * bytecode;
102
  const uint8        pre_context;
103
  const uint16       rule_length,
104
                     classes,
105
                     glyf_attrs,
106
                     features;
107
  const byte         attrid[gr_slatMax];
108
};
109
110
inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype pt) throw()
111
0
: _code(code),
112
0
  _out_index(code._constraint ? 0 : lims.pre_context),
113
0
  _out_length(code._constraint ? 1 : lims.rule_length),
114
0
  _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
115
0
  _stack_depth(0),
116
0
  _in_ctxt_item(false),
117
0
  _slotref(0),
118
0
  _max_ref(0)
119
0
{ }
120
121
122
123
Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
124
           uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
125
           enum passtype pt, byte * * const _out)
126
0
 :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
127
0
    _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
128
0
{
129
#ifdef GRAPHITE2_TELEMETRY
130
    telemetry::category _code_cat(face.tele.code);
131
#endif
132
0
    assert(bytecode_begin != 0);
133
0
    if (bytecode_begin == bytecode_end)
134
0
    {
135
      // ::new (this) Code();
136
0
      return;
137
0
    }
138
0
    assert(bytecode_end > bytecode_begin);
139
0
    const opcode_t *    op_to_fn = Machine::getOpcodeTable();
140
141
    // Allocate code and data target buffers, these sizes are a worst case
142
    // estimate.  Once we know their real sizes the we'll shrink them.
143
0
    if (_out)   _code = reinterpret_cast<instr *>(*_out);
144
0
    else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
145
0
    _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
146
147
0
    if (!_code || !_data) {
148
0
        failure(alloc_failed);
149
0
        return;
150
0
    }
151
152
0
    decoder::limits lims = {
153
0
        bytecode_end,
154
0
        pre_context,
155
0
        rule_length,
156
0
        silf.numClasses(),
157
0
        face.glyphs().numAttrs(),
158
0
        face.numFeatures(),
159
0
        {1,1,1,1,1,1,1,1,
160
0
         1,1,1,1,1,1,1,255,
161
0
         1,1,1,1,1,1,1,1,
162
0
         1,1,1,1,1,1,0,0,
163
0
         0,0,0,0,0,0,0,0,
164
0
         0,0,0,0,0,0,0,0,
165
0
         0,0,0,0,0,0,0, silf.numUser()}
166
0
    };
167
168
0
    decoder dec(lims, *this, pt);
169
0
    if(!dec.load(bytecode_begin, bytecode_end))
170
0
       return;
171
172
    // Is this an empty program?
173
0
    if (_instr_count == 0)
174
0
    {
175
0
      release_buffers();
176
0
      ::new (this) Code();
177
0
      return;
178
0
    }
179
180
    // When we reach the end check we've terminated it correctly
181
0
    if (!is_return(_code[_instr_count-1])) {
182
0
        failure(missing_return);
183
0
        return;
184
0
    }
185
186
0
    assert((_constraint && immutable()) || !_constraint);
187
0
    dec.apply_analysis(_code, _code + _instr_count);
188
0
    _max_ref = dec.max_ref();
189
190
    // Now we know exactly how much code and data the program really needs
191
    // realloc the buffers to exactly the right size so we don't waste any
192
    // memory.
193
0
    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
194
0
    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
195
0
    memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
196
0
    size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
197
0
    if (_out)
198
0
        *_out += total_sz;
199
0
    else
200
0
    {
201
0
      instr * const old_code = _code;
202
0
      _code = static_cast<instr *>(realloc(_code, total_sz));
203
0
      if (!_code) free(old_code);
204
0
    }
205
0
   _data = reinterpret_cast<byte *>(_code + (_instr_count+1));
206
207
0
    if (!_code)
208
0
    {
209
0
        failure(alloc_failed);
210
0
        return;
211
0
    }
212
213
    // Make this RET_ZERO, we should never reach this but just in case ...
214
0
    _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
215
216
#ifdef GRAPHITE2_TELEMETRY
217
    telemetry::count_bytes(_data_size + (_instr_count+1)*sizeof(instr));
218
#endif
219
0
}
220
221
Machine::Code::~Code() throw ()
222
0
{
223
0
    if (_own)
224
0
        release_buffers();
225
0
}
226
227
228
bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
229
0
{
230
0
    _max.bytecode = bc_end;
231
0
    while (bc < bc_end)
232
0
    {
233
0
        const opcode opc = fetch_opcode(bc++);
234
0
        if (opc == vm::MAX_OPCODE)
235
0
            return false;
236
237
0
        analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
238
239
0
        if (!emit_opcode(opc, bc))
240
0
            return false;
241
0
    }
242
243
0
    return bool(_code);
244
0
}
245
246
// Validation check and fixups.
247
//
248
249
opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
250
0
{
251
0
    const byte opc = *bc++;
252
253
    // Do some basic sanity checks based on what we know about the opcode
254
0
    if (!validate_opcode(opc, bc))  return MAX_OPCODE;
255
256
    // And check its arguments as far as possible
257
0
    switch (opcode(opc))
258
0
    {
259
0
        case NOP :
260
0
            break;
261
0
        case PUSH_BYTE :
262
0
        case PUSH_BYTEU :
263
0
        case PUSH_SHORT :
264
0
        case PUSH_SHORTU :
265
0
        case PUSH_LONG :
266
0
            ++_stack_depth;
267
0
            break;
268
0
        case ADD :
269
0
        case SUB :
270
0
        case MUL :
271
0
        case DIV :
272
0
        case MIN_ :
273
0
        case MAX_ :
274
0
        case AND :
275
0
        case OR :
276
0
        case EQUAL :
277
0
        case NOT_EQ :
278
0
        case LESS :
279
0
        case GTR :
280
0
        case LESS_EQ :
281
0
        case GTR_EQ :
282
0
        case BITOR :
283
0
        case BITAND :
284
0
            if (--_stack_depth <= 0)
285
0
                failure(underfull_stack);
286
0
            break;
287
0
        case NEG :
288
0
        case TRUNC8 :
289
0
        case TRUNC16 :
290
0
        case NOT :
291
0
        case BITNOT :
292
0
        case BITSET :
293
0
            if (_stack_depth <= 0)
294
0
                failure(underfull_stack);
295
0
            break;
296
0
        case COND :
297
0
            _stack_depth -= 2;
298
0
            if (_stack_depth <= 0)
299
0
                failure(underfull_stack);
300
0
            break;
301
0
        case NEXT_N :           // runtime checked
302
0
            break;
303
0
        case NEXT :
304
0
        case COPY_NEXT :
305
0
            ++_out_index;
306
0
            if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
307
0
                failure(out_of_range_data);
308
0
            break;
309
0
        case PUT_GLYPH_8BIT_OBS :
310
0
            valid_upto(_max.classes, bc[0]);
311
0
            test_context();
312
0
            break;
313
0
        case PUT_SUBS_8BIT_OBS :
314
0
            test_ref(int8(bc[0]));
315
0
            valid_upto(_max.classes, bc[1]);
316
0
            valid_upto(_max.classes, bc[2]);
317
0
            test_context();
318
0
            break;
319
0
        case PUT_COPY :
320
0
            test_ref(int8(bc[0]));
321
0
            test_context();
322
0
            break;
323
0
        case INSERT :
324
0
            if (_passtype >= PASS_TYPE_POSITIONING)
325
0
                failure(invalid_opcode);
326
0
            ++_out_length;
327
0
            if (_out_index < 0) ++_out_index;
328
0
            if (_out_index < -1 || _out_index >= _out_length)
329
0
                failure(out_of_range_data);
330
0
            break;
331
0
        case DELETE :
332
0
            if (_passtype >= PASS_TYPE_POSITIONING)
333
0
                failure(invalid_opcode);
334
0
            if (_out_index < _max.pre_context)
335
0
                failure(out_of_range_data);
336
0
            --_out_index;
337
0
            --_out_length;
338
0
            if (_out_index < -1 || _out_index > _out_length)
339
0
                failure(out_of_range_data);
340
0
            break;
341
0
        case ASSOC :
342
0
            if (bc[0] == 0)
343
0
                failure(out_of_range_data);
344
0
            for (uint8 num = bc[0]; num; --num)
345
0
                test_ref(int8(bc[num]));
346
0
            test_context();
347
0
            break;
348
0
        case CNTXT_ITEM :
349
0
            valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
350
0
            if (bc + 2 + bc[1] >= _max.bytecode)    failure(jump_past_end);
351
0
            if (_in_ctxt_item)                      failure(nested_context_item);
352
0
            break;
353
0
        case ATTR_SET :
354
0
        case ATTR_ADD :
355
0
        case ATTR_SUB :
356
0
        case ATTR_SET_SLOT :
357
0
            if (--_stack_depth < 0)
358
0
                failure(underfull_stack);
359
0
            valid_upto(gr_slatMax, bc[0]);
360
0
            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
361
0
                failure(out_of_range_data);
362
0
            test_attr(attrCode(bc[0]));
363
0
            test_context();
364
0
            break;
365
0
        case IATTR_SET_SLOT :
366
0
            if (--_stack_depth < 0)
367
0
                failure(underfull_stack);
368
0
            if (valid_upto(gr_slatMax, bc[0]))
369
0
                valid_upto(_max.attrid[bc[0]], bc[1]);
370
0
            test_attr(attrCode(bc[0]));
371
0
            test_context();
372
0
            break;
373
0
        case PUSH_SLOT_ATTR :
374
0
            ++_stack_depth;
375
0
            valid_upto(gr_slatMax, bc[0]);
376
0
            test_ref(int8(bc[1]));
377
0
            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
378
0
                failure(out_of_range_data);
379
0
            test_attr(attrCode(bc[0]));
380
0
            break;
381
0
        case PUSH_GLYPH_ATTR_OBS :
382
0
        case PUSH_ATT_TO_GATTR_OBS :
383
0
            ++_stack_depth;
384
0
            valid_upto(_max.glyf_attrs, bc[0]);
385
0
            test_ref(int8(bc[1]));
386
0
            break;
387
0
        case PUSH_ATT_TO_GLYPH_METRIC :
388
0
        case PUSH_GLYPH_METRIC :
389
0
            ++_stack_depth;
390
0
            valid_upto(kgmetDescent, bc[0]);
391
0
            test_ref(int8(bc[1]));
392
            // level: dp[2] no check necessary
393
0
            break;
394
0
        case PUSH_FEAT :
395
0
            ++_stack_depth;
396
0
            valid_upto(_max.features, bc[0]);
397
0
            test_ref(int8(bc[1]));
398
0
            break;
399
0
        case PUSH_ISLOT_ATTR :
400
0
            ++_stack_depth;
401
0
            if (valid_upto(gr_slatMax, bc[0]))
402
0
            {
403
0
                test_ref(int8(bc[1]));
404
0
                valid_upto(_max.attrid[bc[0]], bc[2]);
405
0
            }
406
0
            test_attr(attrCode(bc[0]));
407
0
            break;
408
0
        case PUSH_IGLYPH_ATTR :// not implemented
409
0
            ++_stack_depth;
410
0
            break;
411
0
        case POP_RET :
412
0
            if (--_stack_depth < 0)
413
0
                failure(underfull_stack);
414
0
            GR_FALLTHROUGH;
415
            // no break
416
0
        case RET_ZERO :
417
0
        case RET_TRUE :
418
0
            break;
419
0
        case IATTR_SET :
420
0
        case IATTR_ADD :
421
0
        case IATTR_SUB :
422
0
            if (--_stack_depth < 0)
423
0
                failure(underfull_stack);
424
0
            if (valid_upto(gr_slatMax, bc[0]))
425
0
                valid_upto(_max.attrid[bc[0]], bc[1]);
426
0
            test_attr(attrCode(bc[0]));
427
0
            test_context();
428
0
            break;
429
0
        case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
430
0
        case PUSH_VERSION :
431
0
            ++_stack_depth;
432
0
            break;
433
0
        case PUT_SUBS :
434
0
            test_ref(int8(bc[0]));
435
0
            valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
436
0
            valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
437
0
            test_context();
438
0
            break;
439
0
        case PUT_SUBS2 :        // not implemented
440
0
        case PUT_SUBS3 :        // not implemented
441
0
            break;
442
0
        case PUT_GLYPH :
443
0
            valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
444
0
            test_context();
445
0
            break;
446
0
        case PUSH_GLYPH_ATTR :
447
0
        case PUSH_ATT_TO_GLYPH_ATTR :
448
0
            ++_stack_depth;
449
0
            valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
450
0
            test_ref(int8(bc[2]));
451
0
            break;
452
0
        case SET_FEAT :
453
0
            valid_upto(_max.features, bc[0]);
454
0
            test_ref(int8(bc[1]));
455
0
            break;
456
0
        default:
457
0
            failure(invalid_opcode);
458
0
            break;
459
0
    }
460
461
0
    return bool(_code) ? opcode(opc) : MAX_OPCODE;
462
0
}
463
464
465
void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
466
0
{
467
0
  switch (opc)
468
0
  {
469
0
    case DELETE :
470
0
      _code._delete = true;
471
0
      break;
472
0
    case ASSOC :
473
0
      set_changed(0);
474
//      for (uint8 num = arg[0]; num; --num)
475
//        _analysis.set_noref(num);
476
0
      break;
477
0
    case PUT_GLYPH_8BIT_OBS :
478
0
    case PUT_GLYPH :
479
0
      _code._modify = true;
480
0
      set_changed(0);
481
0
      break;
482
0
    case ATTR_SET :
483
0
    case ATTR_ADD :
484
0
    case ATTR_SUB :
485
0
    case ATTR_SET_SLOT :
486
0
    case IATTR_SET_SLOT :
487
0
    case IATTR_SET :
488
0
    case IATTR_ADD :
489
0
    case IATTR_SUB :
490
0
      set_noref(0);
491
0
      break;
492
0
    case NEXT :
493
0
    case COPY_NEXT :
494
0
      ++_slotref;
495
0
      _contexts[_slotref] = context(uint8(_code._instr_count+1));
496
      // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
497
0
      break;
498
0
    case INSERT :
499
0
      if (_slotref >= 0) --_slotref;
500
0
      _code._modify = true;
501
0
      break;
502
0
    case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
503
0
    case PUT_SUBS :
504
0
      _code._modify = true;
505
0
      set_changed(0);
506
0
      GR_FALLTHROUGH;
507
      // no break
508
0
    case PUT_COPY :
509
0
      if (arg[0] != 0) { set_changed(0); _code._modify = true; }
510
0
      set_ref(arg[0]);
511
0
      break;
512
0
    case PUSH_GLYPH_ATTR_OBS :
513
0
    case PUSH_SLOT_ATTR :
514
0
    case PUSH_GLYPH_METRIC :
515
0
    case PUSH_ATT_TO_GATTR_OBS :
516
0
    case PUSH_ATT_TO_GLYPH_METRIC :
517
0
    case PUSH_ISLOT_ATTR :
518
0
    case PUSH_FEAT :
519
0
    case SET_FEAT :
520
0
      set_ref(arg[1]);
521
0
      break;
522
0
    case PUSH_ATT_TO_GLYPH_ATTR :
523
0
    case PUSH_GLYPH_ATTR :
524
0
      set_ref(arg[2]);
525
0
      break;
526
0
    default:
527
0
        break;
528
0
  }
529
0
}
530
531
532
bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
533
0
{
534
0
    const opcode_t * op_to_fn = Machine::getOpcodeTable();
535
0
    const opcode_t & op       = op_to_fn[opc];
536
0
    if (op.impl[_code._constraint] == 0)
537
0
    {
538
0
        failure(unimplemented_opcode_used);
539
0
        return false;
540
0
    }
541
542
0
    const size_t     param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
543
544
    // Add this instruction
545
0
    *_instr++ = op.impl[_code._constraint];
546
0
    ++_code._instr_count;
547
548
    // Grab the parameters
549
0
    if (param_sz) {
550
0
        memcpy(_data, bc, param_sz * sizeof(byte));
551
0
        bc               += param_sz;
552
0
        _data            += param_sz;
553
0
        _code._data_size += param_sz;
554
0
    }
555
556
    // recursively decode a context item so we can split the skip into
557
    // instruction and data portions.
558
0
    if (opc == CNTXT_ITEM)
559
0
    {
560
0
        assert(_out_index == 0);
561
0
        _in_ctxt_item = true;
562
0
        _out_index = _max.pre_context + int8(_data[-2]);
563
0
        _slotref = int8(_data[-2]);
564
0
        _out_length = _max.rule_length;
565
566
0
        const size_t ctxt_start = _code._instr_count;
567
0
        byte & instr_skip = _data[-1];
568
0
        byte & data_skip  = *_data++;
569
0
        ++_code._data_size;
570
0
        const byte *curr_end = _max.bytecode;
571
572
0
        if (load(bc, bc + instr_skip))
573
0
        {
574
0
            bc += instr_skip;
575
0
            data_skip  = instr_skip - byte(_code._instr_count - ctxt_start);
576
0
            instr_skip =  byte(_code._instr_count - ctxt_start);
577
0
            _max.bytecode = curr_end;
578
579
0
            _out_length = 1;
580
0
            _out_index = 0;
581
0
            _slotref = 0;
582
0
            _in_ctxt_item = false;
583
0
        }
584
0
        else
585
0
        {
586
0
            _out_index = 0;
587
0
            _slotref = 0;
588
0
            return false;
589
0
        }
590
0
    }
591
592
0
    return bool(_code);
593
0
}
594
595
596
void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
597
0
{
598
    // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
599
0
    int tempcount = 0;
600
0
    if (_code._constraint) return;
601
602
0
    const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
603
0
    for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
604
0
    {
605
0
        if (!c->flags.referenced || !c->flags.changed) continue;
606
607
0
        instr * const tip = code + c->codeRef + tempcount;
608
0
        memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
609
0
        *tip = temp_copy;
610
0
        ++code_end;
611
0
        ++tempcount;
612
0
        _code._delete = true;
613
0
    }
614
615
0
    _code._instr_count = code_end - code;
616
0
}
617
618
619
inline
620
bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
621
0
{
622
0
    if (opc >= MAX_OPCODE)
623
0
    {
624
0
        failure(invalid_opcode);
625
0
        return false;
626
0
    }
627
0
    const opcode_t & op = Machine::getOpcodeTable()[opc];
628
0
    if (op.impl[_code._constraint] == 0)
629
0
    {
630
0
        failure(unimplemented_opcode_used);
631
0
        return false;
632
0
    }
633
0
    if (op.param_sz == VARARGS && bc >= _max.bytecode)
634
0
    {
635
0
        failure(arguments_exhausted);
636
0
        return false;
637
0
    }
638
0
    const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
639
0
    if (bc - 1 + param_sz >= _max.bytecode)
640
0
    {
641
0
        failure(arguments_exhausted);
642
0
        return false;
643
0
    }
644
0
    return true;
645
0
}
646
647
648
bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
649
0
{
650
0
    const bool t = (limit != 0) && (x < limit);
651
0
    if (!t) failure(out_of_range_data);
652
0
    return t;
653
0
}
654
655
inline
656
bool Machine::Code::decoder::test_ref(int8 index) const throw()
657
0
{
658
0
    if (_code._constraint && !_in_ctxt_item)
659
0
    {
660
0
        if (index > 0 || -index > _max.pre_context)
661
0
        {
662
0
            failure(out_of_range_data);
663
0
            return false;
664
0
        }
665
0
    }
666
0
    else
667
0
    {
668
0
      if (_max.rule_length == 0
669
0
          || (_slotref + _max.pre_context + index >= _max.rule_length)
670
0
          || (_slotref + _max.pre_context + index < 0))
671
0
      {
672
0
        failure(out_of_range_data);
673
0
        return false;
674
0
      }
675
0
    }
676
0
    return true;
677
0
}
678
679
bool Machine::Code::decoder::test_context() const throw()
680
0
{
681
0
    if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
682
0
    {
683
0
        failure(out_of_range_data);
684
0
        return false;
685
0
    }
686
0
    return true;
687
0
}
688
689
bool Machine::Code::decoder::test_attr(attrCode) const throw()
690
0
{
691
#if 0   // This code is coming but causes backward compatibility problems.
692
    if (_passtype < PASS_TYPE_POSITIONING)
693
    {
694
        if (attr != gr_slatBreak && attr != gr_slatDir && attr != gr_slatUserDefn
695
                                 && attr != gr_slatCompRef)
696
        {
697
            failure(out_of_range_data);
698
            return false;
699
        }
700
    }
701
#endif
702
0
    return true;
703
0
}
704
705
inline
706
0
void Machine::Code::failure(const status_t s) throw() {
707
0
    release_buffers();
708
0
    _status = s;
709
0
}
710
711
712
inline
713
0
void Machine::Code::decoder::set_ref(int index) throw() {
714
0
    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
715
0
    _contexts[index + _slotref].flags.referenced = true;
716
0
    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
717
0
}
718
719
720
inline
721
0
void Machine::Code::decoder::set_noref(int index) throw() {
722
0
    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
723
0
    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
724
0
}
725
726
727
inline
728
0
void Machine::Code::decoder::set_changed(int index) throw() {
729
0
    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
730
0
    _contexts[index + _slotref].flags.changed= true;
731
0
    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
732
0
}
733
734
735
void Machine::Code::release_buffers() throw()
736
0
{
737
0
    if (_own)
738
0
        free(_code);
739
0
    _code = 0;
740
0
    _data = 0;
741
0
    _own  = false;
742
0
}
743
744
745
int32 Machine::Code::run(Machine & m, slotref * & map) const
746
0
{
747
//    assert(_own);
748
0
    assert(*this);          // Check we are actually runnable
749
750
0
    if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
751
0
        || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
752
0
    {
753
0
        m._status = Machine::slot_offset_out_bounds;
754
0
        return 1;
755
//        return m.run(_code, _data, map);
756
0
    }
757
758
0
    return  m.run(_code, _data, map);
759
0
}