Coverage Report

Created: 2025-07-07 10:01

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