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 
is_return(const instr i)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 {
context__anon17f2ddcb0111::context69     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);
max_ref()90     byte        max_ref() { return _max_ref; }
out_index() const91     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();
failure(const status_t s) const105     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 
decoder(limits & lims,Code & code,enum passtype pt)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 
Code(bool is_constraint,const byte * bytecode_begin,const byte * const bytecode_end,uint8 pre_context,uint16 rule_length,const Silf & silf,const Face & face,enum passtype pt,byte ** const _out)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 
~Code()244 Machine::Code::~Code() throw ()
245 {
246     if (_own)
247         release_buffers();
248 }
249 
250 
load(const byte * bc,const byte * bc_end)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 
fetch_opcode(const byte * bc)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 
analyse_opcode(const opcode opc,const int8 * arg)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 
emit_opcode(opcode opc,const byte * & bc)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 
apply_analysis(instr * const code,instr * code_end)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
validate_opcode(const byte opc,const byte * const bc)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 
valid_upto(const uint16 limit,const uint16 x) const671 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
test_ref(int8 index) const679 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 
test_context() const702 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 
test_attr(attrCode) const712 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
failure(const status_t s)729 void Machine::Code::failure(const status_t s) throw() {
730     release_buffers();
731     _status = s;
732 }
733 
734 
735 inline
set_ref(int index)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
set_noref(int index)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
set_changed(int index)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 
release_buffers()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 
run(Machine & m,slotref * & map) const768 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 }
783