tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Code.cpp (23052B)


      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 inline bool is_return(const instr i) {
     60    const opcode_t * opmap = Machine::getOpcodeTable();
     61    const instr pop_ret  = *opmap[POP_RET].impl,
     62                ret_zero = *opmap[RET_ZERO].impl,
     63                ret_true = *opmap[RET_TRUE].impl;
     64    return i == pop_ret || i == ret_zero || i == ret_true;
     65 }
     66 
     67 struct context
     68 {
     69    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    byte        max_ref() { return _max_ref; }
     91    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    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 : _code(code),
    135  _out_index(code._constraint ? 0 : lims.pre_context),
    136  _out_length(code._constraint ? 1 : lims.rule_length),
    137  _instr(code._code), _data(code._data), _max(lims), _passtype(pt),
    138  _stack_depth(0),
    139  _in_ctxt_item(false),
    140  _slotref(0),
    141  _max_ref(0)
    142 { }
    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 :  _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
    150    _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
    151 {
    152 #ifdef GRAPHITE2_TELEMETRY
    153    telemetry::category _code_cat(face.tele.code);
    154 #endif
    155    assert(bytecode_begin != 0);
    156    if (bytecode_begin == bytecode_end)
    157    {
    158      // ::new (this) Code();
    159      return;
    160    }
    161    assert(bytecode_end > bytecode_begin);
    162    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    if (_out)   _code = reinterpret_cast<instr *>(*_out);
    167    else        _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin, 1, is_constraint ? 0 : rule_length)));
    168    _data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
    169 
    170    if (!_code || !_data) {
    171        failure(alloc_failed);
    172        return;
    173    }
    174 
    175    decoder::limits lims = {
    176        bytecode_end,
    177        pre_context,
    178        rule_length,
    179        silf.numClasses(),
    180        face.glyphs().numAttrs(),
    181        face.numFeatures(),
    182        {1,1,1,1,1,1,1,1,
    183         1,1,1,1,1,1,1,255,
    184         1,1,1,1,1,1,1,1,
    185         1,1,1,1,1,1,0,0,
    186         0,0,0,0,0,0,0,0,
    187         0,0,0,0,0,0,0,0,
    188         0,0,0,0,0,0,0, silf.numUser()}
    189    };
    190 
    191    decoder dec(lims, *this, pt);
    192    if(!dec.load(bytecode_begin, bytecode_end))
    193       return;
    194 
    195    // Is this an empty program?
    196    if (_instr_count == 0)
    197    {
    198      release_buffers();
    199      ::new (this) Code();
    200      return;
    201    }
    202 
    203    // When we reach the end check we've terminated it correctly
    204    if (!is_return(_code[_instr_count-1])) {
    205        failure(missing_return);
    206        return;
    207    }
    208 
    209    assert((_constraint && immutable()) || !_constraint);
    210    dec.apply_analysis(_code, _code + _instr_count);
    211    _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    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_instr_count));
    217    assert((bytecode_end - bytecode_begin) >= ptrdiff_t(_data_size));
    218    memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
    219    size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
    220    if (_out)
    221        *_out += total_sz;
    222    else
    223    {
    224      instr * const old_code = _code;
    225      _code = static_cast<instr *>(realloc(_code, total_sz));
    226      if (!_code) free(old_code);
    227    }
    228   _data = reinterpret_cast<byte *>(_code + (_instr_count+1));
    229 
    230    if (!_code)
    231    {
    232        failure(alloc_failed);
    233        return;
    234    }
    235 
    236    // Make this RET_ZERO, we should never reach this but just in case ...
    237    _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 }
    243 
    244 Machine::Code::~Code() throw ()
    245 {
    246    if (_own)
    247        release_buffers();
    248 }
    249 
    250 
    251 bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
    252 {
    253    _max.bytecode = bc_end;
    254    while (bc < bc_end)
    255    {
    256        const opcode opc = fetch_opcode(bc++);
    257        if (opc == vm::MAX_OPCODE)
    258            return false;
    259 
    260        analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
    261 
    262        if (!emit_opcode(opc, bc))
    263            return false;
    264    }
    265 
    266    return bool(_code);
    267 }
    268 
    269 // Validation check and fixups.
    270 //
    271 
    272 opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
    273 {
    274    const byte opc = *bc++;
    275 
    276    // Do some basic sanity checks based on what we know about the opcode
    277    if (!validate_opcode(opc, bc))  return MAX_OPCODE;
    278 
    279    // And check its arguments as far as possible
    280    switch (opcode(opc))
    281    {
    282        case NOP :
    283            break;
    284        case PUSH_BYTE :
    285        case PUSH_BYTEU :
    286        case PUSH_SHORT :
    287        case PUSH_SHORTU :
    288        case PUSH_LONG :
    289            ++_stack_depth;
    290            break;
    291        case ADD :
    292        case SUB :
    293        case MUL :
    294        case DIV :
    295        case MIN_ :
    296        case MAX_ :
    297        case AND :
    298        case OR :
    299        case EQUAL :
    300        case NOT_EQ :
    301        case LESS :
    302        case GTR :
    303        case LESS_EQ :
    304        case GTR_EQ :
    305        case BITOR :
    306        case BITAND :
    307            if (--_stack_depth <= 0)
    308                failure(underfull_stack);
    309            break;
    310        case NEG :
    311        case TRUNC8 :
    312        case TRUNC16 :
    313        case NOT :
    314        case BITNOT :
    315        case BITSET :
    316            if (_stack_depth <= 0)
    317                failure(underfull_stack);
    318            break;
    319        case COND :
    320            _stack_depth -= 2;
    321            if (_stack_depth <= 0)
    322                failure(underfull_stack);
    323            break;
    324        case NEXT_N :           // runtime checked
    325            break;
    326        case NEXT :
    327        case COPY_NEXT :
    328            ++_out_index;
    329            if (_out_index < -1 || _out_index > _out_length || _slotref > _max.rule_length)
    330                failure(out_of_range_data);
    331            break;
    332        case PUT_GLYPH_8BIT_OBS :
    333            valid_upto(_max.classes, bc[0]);
    334            test_context();
    335            break;
    336        case PUT_SUBS_8BIT_OBS :
    337            test_ref(int8(bc[0]));
    338            valid_upto(_max.classes, bc[1]);
    339            valid_upto(_max.classes, bc[2]);
    340            test_context();
    341            break;
    342        case PUT_COPY :
    343            test_ref(int8(bc[0]));
    344            test_context();
    345            break;
    346        case INSERT :
    347            if (_passtype >= PASS_TYPE_POSITIONING)
    348                failure(invalid_opcode);
    349            ++_out_length;
    350            if (_out_index < 0) ++_out_index;
    351            if (_out_index < -1 || _out_index >= _out_length)
    352                failure(out_of_range_data);
    353            break;
    354        case DELETE :
    355            if (_passtype >= PASS_TYPE_POSITIONING)
    356                failure(invalid_opcode);
    357            if (_out_index < _max.pre_context)
    358                failure(out_of_range_data);
    359            --_out_index;
    360            --_out_length;
    361            if (_out_index < -1 || _out_index > _out_length)
    362                failure(out_of_range_data);
    363            break;
    364        case ASSOC :
    365            if (bc[0] == 0)
    366                failure(out_of_range_data);
    367            for (uint8 num = bc[0]; num; --num)
    368                test_ref(int8(bc[num]));
    369            test_context();
    370            break;
    371        case CNTXT_ITEM :
    372            valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
    373            if (bc + 2 + bc[1] >= _max.bytecode)    failure(jump_past_end);
    374            if (_in_ctxt_item)                      failure(nested_context_item);
    375            break;
    376        case ATTR_SET :
    377        case ATTR_ADD :
    378        case ATTR_SUB :
    379        case ATTR_SET_SLOT :
    380            if (--_stack_depth < 0)
    381                failure(underfull_stack);
    382            valid_upto(gr_slatMax, bc[0]);
    383            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
    384                failure(out_of_range_data);
    385            test_attr(attrCode(bc[0]));
    386            test_context();
    387            break;
    388        case IATTR_SET_SLOT :
    389            if (--_stack_depth < 0)
    390                failure(underfull_stack);
    391            if (valid_upto(gr_slatMax, bc[0]))
    392                valid_upto(_max.attrid[bc[0]], bc[1]);
    393            test_attr(attrCode(bc[0]));
    394            test_context();
    395            break;
    396        case PUSH_SLOT_ATTR :
    397            ++_stack_depth;
    398            valid_upto(gr_slatMax, bc[0]);
    399            test_ref(int8(bc[1]));
    400            if (attrCode(bc[0]) == gr_slatUserDefn)     // use IATTR for user attributes
    401                failure(out_of_range_data);
    402            test_attr(attrCode(bc[0]));
    403            break;
    404        case PUSH_GLYPH_ATTR_OBS :
    405        case PUSH_ATT_TO_GATTR_OBS :
    406            ++_stack_depth;
    407            valid_upto(_max.glyf_attrs, bc[0]);
    408            test_ref(int8(bc[1]));
    409            break;
    410        case PUSH_ATT_TO_GLYPH_METRIC :
    411        case PUSH_GLYPH_METRIC :
    412            ++_stack_depth;
    413            valid_upto(kgmetDescent, bc[0]);
    414            test_ref(int8(bc[1]));
    415            // level: dp[2] no check necessary
    416            break;
    417        case PUSH_FEAT :
    418            ++_stack_depth;
    419            valid_upto(_max.features, bc[0]);
    420            test_ref(int8(bc[1]));
    421            break;
    422        case PUSH_ISLOT_ATTR :
    423            ++_stack_depth;
    424            if (valid_upto(gr_slatMax, bc[0]))
    425            {
    426                test_ref(int8(bc[1]));
    427                valid_upto(_max.attrid[bc[0]], bc[2]);
    428            }
    429            test_attr(attrCode(bc[0]));
    430            break;
    431        case PUSH_IGLYPH_ATTR :// not implemented
    432            ++_stack_depth;
    433            break;
    434        case POP_RET :
    435            if (--_stack_depth < 0)
    436                failure(underfull_stack);
    437            GR_FALLTHROUGH;
    438            // no break
    439        case RET_ZERO :
    440        case RET_TRUE :
    441            break;
    442        case IATTR_SET :
    443        case IATTR_ADD :
    444        case IATTR_SUB :
    445            if (--_stack_depth < 0)
    446                failure(underfull_stack);
    447            if (valid_upto(gr_slatMax, bc[0]))
    448                valid_upto(_max.attrid[bc[0]], bc[1]);
    449            test_attr(attrCode(bc[0]));
    450            test_context();
    451            break;
    452        case PUSH_PROC_STATE :  // dummy: dp[0] no check necessary
    453        case PUSH_VERSION :
    454            ++_stack_depth;
    455            break;
    456        case PUT_SUBS :
    457            test_ref(int8(bc[0]));
    458            valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
    459            valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
    460            test_context();
    461            break;
    462        case PUT_SUBS2 :        // not implemented
    463        case PUT_SUBS3 :        // not implemented
    464            break;
    465        case PUT_GLYPH :
    466            valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
    467            test_context();
    468            break;
    469        case PUSH_GLYPH_ATTR :
    470        case PUSH_ATT_TO_GLYPH_ATTR :
    471            ++_stack_depth;
    472            valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
    473            test_ref(int8(bc[2]));
    474            break;
    475        case SET_FEAT :
    476            valid_upto(_max.features, bc[0]);
    477            test_ref(int8(bc[1]));
    478            break;
    479        default:
    480            failure(invalid_opcode);
    481            break;
    482    }
    483 
    484    return bool(_code) ? opcode(opc) : MAX_OPCODE;
    485 }
    486 
    487 
    488 void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8  * arg) throw()
    489 {
    490  switch (opc)
    491  {
    492    case DELETE :
    493      _code._delete = true;
    494      break;
    495    case ASSOC :
    496      set_changed(0);
    497 //      for (uint8 num = arg[0]; num; --num)
    498 //        _analysis.set_noref(num);
    499      break;
    500    case PUT_GLYPH_8BIT_OBS :
    501    case PUT_GLYPH :
    502      _code._modify = true;
    503      set_changed(0);
    504      break;
    505    case ATTR_SET :
    506    case ATTR_ADD :
    507    case ATTR_SUB :
    508    case ATTR_SET_SLOT :
    509    case IATTR_SET_SLOT :
    510    case IATTR_SET :
    511    case IATTR_ADD :
    512    case IATTR_SUB :
    513      set_noref(0);
    514      break;
    515    case NEXT :
    516    case COPY_NEXT :
    517      ++_slotref;
    518      _contexts[_slotref] = context(uint8(_code._instr_count+1));
    519      // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
    520      break;
    521    case INSERT :
    522      if (_slotref >= 0) --_slotref;
    523      _code._modify = true;
    524      break;
    525    case PUT_SUBS_8BIT_OBS :    // slotref on 1st parameter
    526    case PUT_SUBS :
    527      _code._modify = true;
    528      set_changed(0);
    529      GR_FALLTHROUGH;
    530      // no break
    531    case PUT_COPY :
    532      if (arg[0] != 0) { set_changed(0); _code._modify = true; }
    533      set_ref(arg[0]);
    534      break;
    535    case PUSH_GLYPH_ATTR_OBS :
    536    case PUSH_SLOT_ATTR :
    537    case PUSH_GLYPH_METRIC :
    538    case PUSH_ATT_TO_GATTR_OBS :
    539    case PUSH_ATT_TO_GLYPH_METRIC :
    540    case PUSH_ISLOT_ATTR :
    541    case PUSH_FEAT :
    542    case SET_FEAT :
    543      set_ref(arg[1]);
    544      break;
    545    case PUSH_ATT_TO_GLYPH_ATTR :
    546    case PUSH_GLYPH_ATTR :
    547      set_ref(arg[2]);
    548      break;
    549    default:
    550        break;
    551  }
    552 }
    553 
    554 
    555 bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
    556 {
    557    const opcode_t * op_to_fn = Machine::getOpcodeTable();
    558    const opcode_t & op       = op_to_fn[opc];
    559    if (op.impl[_code._constraint] == 0)
    560    {
    561        failure(unimplemented_opcode_used);
    562        return false;
    563    }
    564 
    565    const size_t     param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
    566 
    567    // Add this instruction
    568    *_instr++ = op.impl[_code._constraint];
    569    ++_code._instr_count;
    570 
    571    // Grab the parameters
    572    if (param_sz) {
    573        memcpy(_data, bc, param_sz * sizeof(byte));
    574        bc               += param_sz;
    575        _data            += param_sz;
    576        _code._data_size += param_sz;
    577    }
    578 
    579    // recursively decode a context item so we can split the skip into
    580    // instruction and data portions.
    581    if (opc == CNTXT_ITEM)
    582    {
    583        assert(_out_index == 0);
    584        _in_ctxt_item = true;
    585        _out_index = _max.pre_context + int8(_data[-2]);
    586        _slotref = int8(_data[-2]);
    587        _out_length = _max.rule_length;
    588 
    589        const size_t ctxt_start = _code._instr_count;
    590        byte & instr_skip = _data[-1];
    591        byte & data_skip  = *_data++;
    592        ++_code._data_size;
    593        const byte *curr_end = _max.bytecode;
    594 
    595        if (load(bc, bc + instr_skip))
    596        {
    597            bc += instr_skip;
    598            data_skip  = instr_skip - byte(_code._instr_count - ctxt_start);
    599            instr_skip =  byte(_code._instr_count - ctxt_start);
    600            _max.bytecode = curr_end;
    601 
    602            _out_length = 1;
    603            _out_index = 0;
    604            _slotref = 0;
    605            _in_ctxt_item = false;
    606        }
    607        else
    608        {
    609            _out_index = 0;
    610            _slotref = 0;
    611            return false;
    612        }
    613    }
    614 
    615    return bool(_code);
    616 }
    617 
    618 
    619 void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
    620 {
    621    // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
    622    int tempcount = 0;
    623    if (_code._constraint) return;
    624 
    625    const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
    626    for (const context * c = _contexts, * const ce = c + _slotref; c < ce; ++c)
    627    {
    628        if (!c->flags.referenced || !c->flags.changed) continue;
    629 
    630        instr * const tip = code + c->codeRef + tempcount;
    631        memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
    632        *tip = temp_copy;
    633        ++code_end;
    634        ++tempcount;
    635        _code._delete = true;
    636    }
    637 
    638    _code._instr_count = code_end - code;
    639 }
    640 
    641 
    642 inline
    643 bool Machine::Code::decoder::validate_opcode(const byte opc, const byte * const bc)
    644 {
    645    if (opc >= MAX_OPCODE)
    646    {
    647        failure(invalid_opcode);
    648        return false;
    649    }
    650    const opcode_t & op = Machine::getOpcodeTable()[opc];
    651    if (op.impl[_code._constraint] == 0)
    652    {
    653        failure(unimplemented_opcode_used);
    654        return false;
    655    }
    656    if (op.param_sz == VARARGS && bc >= _max.bytecode)
    657    {
    658        failure(arguments_exhausted);
    659        return false;
    660    }
    661    const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
    662    if (bc - 1 + param_sz >= _max.bytecode)
    663    {
    664        failure(arguments_exhausted);
    665        return false;
    666    }
    667    return true;
    668 }
    669 
    670 
    671 bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
    672 {
    673    const bool t = (limit != 0) && (x < limit);
    674    if (!t) failure(out_of_range_data);
    675    return t;
    676 }
    677 
    678 inline
    679 bool Machine::Code::decoder::test_ref(int8 index) const throw()
    680 {
    681    if (_code._constraint && !_in_ctxt_item)
    682    {
    683        if (index > 0 || -index > _max.pre_context)
    684        {
    685            failure(out_of_range_data);
    686            return false;
    687        }
    688    }
    689    else
    690    {
    691      if (_max.rule_length == 0
    692          || (_slotref + _max.pre_context + index >= _max.rule_length)
    693          || (_slotref + _max.pre_context + index < 0))
    694      {
    695        failure(out_of_range_data);
    696        return false;
    697      }
    698    }
    699    return true;
    700 }
    701 
    702 bool Machine::Code::decoder::test_context() const throw()
    703 {
    704    if (_out_index >= _out_length || _out_index < 0 || _slotref >= NUMCONTEXTS - 1)
    705    {
    706        failure(out_of_range_data);
    707        return false;
    708    }
    709    return true;
    710 }
    711 
    712 bool Machine::Code::decoder::test_attr(attrCode) const throw()
    713 {
    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    return true;
    726 }
    727 
    728 inline
    729 void Machine::Code::failure(const status_t s) throw() {
    730    release_buffers();
    731    _status = s;
    732 }
    733 
    734 
    735 inline
    736 void Machine::Code::decoder::set_ref(int index) throw() {
    737    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
    738    _contexts[index + _slotref].flags.referenced = true;
    739    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
    740 }
    741 
    742 
    743 inline
    744 void Machine::Code::decoder::set_noref(int index) throw() {
    745    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
    746    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
    747 }
    748 
    749 
    750 inline
    751 void Machine::Code::decoder::set_changed(int index) throw() {
    752    if (index + _slotref < 0 || index + _slotref >= NUMCONTEXTS) return;
    753    _contexts[index + _slotref].flags.changed= true;
    754    if (index + _slotref > _max_ref) _max_ref = index + _slotref;
    755 }
    756 
    757 
    758 void Machine::Code::release_buffers() throw()
    759 {
    760    if (_own)
    761        free(_code);
    762    _code = 0;
    763    _data = 0;
    764    _own  = false;
    765 }
    766 
    767 
    768 int32 Machine::Code::run(Machine & m, slotref * & map) const
    769 {
    770 //    assert(_own);
    771    assert(*this);          // Check we are actually runnable
    772 
    773    if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
    774        || m.slotMap()[_max_ref + m.slotMap().context()] == 0)
    775    {
    776        m._status = Machine::slot_offset_out_bounds;
    777        return 1;
    778 //        return m.run(_code, _data, map);
    779    }
    780 
    781    return  m.run(_code, _data, map);
    782 }