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/Machine.h"
39 : #include "inc/Silf.h"
40 : #include "inc/Face.h"
41 : #include "inc/Rule.h"
42 :
43 : #include <cstdio>
44 :
45 : #ifdef NDEBUG
46 : #ifdef __GNUC__
47 : #pragma GCC diagnostic ignored "-Wunused-parameter"
48 : #endif
49 : #endif
50 :
51 :
52 : using namespace graphite2;
53 : using namespace vm;
54 :
55 : namespace {
56 :
57 0 : inline bool is_return(const instr i) {
58 0 : const opcode_t * opmap = Machine::getOpcodeTable();
59 0 : const instr pop_ret = *opmap[POP_RET].impl,
60 0 : ret_zero = *opmap[RET_ZERO].impl,
61 0 : ret_true = *opmap[RET_TRUE].impl;
62 0 : return i == pop_ret || i == ret_zero || i == ret_true;
63 : }
64 :
65 : struct context
66 : {
67 0 : context(uint8 ref=0) : codeRef(ref) {flags.changed=false; flags.referenced=false; flags.inserted=false;}
68 : struct {
69 : uint8 changed:1,
70 : referenced:1,
71 : inserted:1;
72 : } flags;
73 : uint8 codeRef;
74 : };
75 :
76 : } // end namespace
77 :
78 :
79 : class Machine::Code::decoder
80 : {
81 : public:
82 : struct limits;
83 : struct analysis
84 : {
85 : uint8 slotref;
86 : context contexts[256];
87 : byte max_ref;
88 :
89 0 : analysis() : slotref(0), max_ref(0) {};
90 : void set_ref(int index) throw();
91 : void set_changed(int index) throw();
92 :
93 : };
94 :
95 : decoder(const limits & lims, Code &code) throw();
96 :
97 : bool load(const byte * bc_begin, const byte * bc_end);
98 : void apply_analysis(instr * const code, instr * code_end);
99 0 : byte max_ref() { return _analysis.max_ref; }
100 : int pre_context() const { return _pre_context; }
101 :
102 : private:
103 : opcode fetch_opcode(const byte * bc);
104 : void analyse_opcode(const opcode, const int8 * const dp) throw();
105 : bool emit_opcode(opcode opc, const byte * & bc);
106 : bool validate_opcode(const opcode opc, const byte * const bc);
107 : bool valid_upto(const uint16 limit, const uint16 x) const throw();
108 0 : void failure(const status_t s) const throw() { _code.failure(s); }
109 :
110 : Code & _code;
111 : int _pre_context;
112 : uint16 _rule_length;
113 : instr * _instr;
114 : byte * _data;
115 : const limits & _max;
116 : analysis _analysis;
117 : };
118 :
119 :
120 : struct Machine::Code::decoder::limits
121 : {
122 : const byte * const bytecode;
123 : const uint8 pre_context;
124 : const uint16 rule_length,
125 : classes,
126 : glyf_attrs,
127 : features;
128 : const byte attrid[gr_slatMax];
129 : };
130 :
131 0 : inline Machine::Code::decoder::decoder(const limits & lims, Code &code) throw()
132 : : _code(code),
133 : _pre_context(code._constraint ? 0 : lims.pre_context),
134 : _rule_length(code._constraint ? 1 : lims.rule_length),
135 0 : _instr(code._code), _data(code._data), _max(lims)
136 0 : { }
137 :
138 :
139 :
140 0 : Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
141 : uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face)
142 : : _code(0), _data_size(0), _instr_count(0), _status(loaded),
143 0 : _constraint(is_constraint), _modify(false), _delete(false), _own(true)
144 : {
145 0 : assert(bytecode_begin != 0);
146 0 : if (bytecode_begin == bytecode_end)
147 : {
148 0 : ::new (this) Code();
149 0 : return;
150 : }
151 0 : assert(bytecode_end > bytecode_begin);
152 0 : const opcode_t * op_to_fn = Machine::getOpcodeTable();
153 :
154 : // Allocate code and dat target buffers, these sizes are a worst case
155 : // estimate. Once we know their real sizes the we'll shrink them.
156 : _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
157 0 : * sizeof(instr)));
158 : _data = static_cast<byte *>(malloc((bytecode_end - bytecode_begin)
159 0 : * sizeof(byte)));
160 :
161 0 : if (!_code || !_data) {
162 0 : failure(alloc_failed);
163 0 : return;
164 : }
165 :
166 : const decoder::limits lims = {
167 : bytecode_end,
168 : pre_context,
169 : rule_length,
170 0 : silf.numClasses(),
171 0 : face.getGlyphFaceCache()->numAttrs(),
172 0 : face.numFeatures(),
173 : {1,1,1,1,1,1,1,1,
174 : 1,1,1,1,1,1,1,255,
175 : 1,1,1,1,1,1,1,1,
176 : 1,1,1,1,1,1,0,0,
177 : 0,0,0,0,0,0,0,0,
178 : 0,0,0,0,0,0,0,0,
179 0 : 0,0,0,0,0,0,0, silf.numUser()}
180 0 : };
181 :
182 0 : decoder dec(lims, *this);
183 0 : if(!dec.load(bytecode_begin, bytecode_end))
184 0 : return;
185 :
186 : // Is this an empty program?
187 0 : if (_instr_count == 0)
188 : {
189 0 : release_buffers();
190 0 : ::new (this) Code();
191 0 : return;
192 : }
193 :
194 : // When we reach the end check we've terminated it correctly
195 0 : if (!is_return(_code[_instr_count-1])) {
196 0 : failure(missing_return);
197 0 : return;
198 : }
199 :
200 0 : assert((_constraint && immutable()) || !_constraint);
201 0 : dec.apply_analysis(_code, _code + _instr_count);
202 0 : _max_ref = dec.max_ref();
203 :
204 : // Now we know exactly how much code and data the program really needs
205 : // realloc the buffers to exactly the right size so we don't waste any
206 : // memory.
207 0 : assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_instr_count));
208 0 : assert((bytecode_end - bytecode_begin) >= std::ptrdiff_t(_data_size));
209 0 : _code = static_cast<instr *>(realloc(_code, (_instr_count+1)*sizeof(instr)));
210 0 : _data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
211 :
212 : // Make this RET_ZERO, we should never reach this but just in case ...
213 0 : _code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
214 :
215 0 : if (!_code)
216 0 : failure(alloc_failed);
217 : }
218 :
219 0 : Machine::Code::~Code() throw ()
220 : {
221 0 : if (_own)
222 0 : release_buffers();
223 0 : }
224 :
225 :
226 0 : bool Machine::Code::decoder::load(const byte * bc, const byte * bc_end)
227 : {
228 0 : while (bc < bc_end)
229 : {
230 0 : const opcode opc = fetch_opcode(bc++);
231 0 : if (opc == vm::MAX_OPCODE)
232 0 : return false;
233 :
234 0 : analyse_opcode(opc, reinterpret_cast<const int8 *>(bc));
235 :
236 0 : if (!emit_opcode(opc, bc))
237 0 : return false;
238 : }
239 :
240 0 : return bool(_code);
241 : }
242 :
243 : // Validation check and fixups.
244 : //
245 :
246 0 : opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
247 : {
248 0 : const opcode opc = opcode(*bc++);
249 :
250 : // Do some basic sanity checks based on what we know about the opcode
251 0 : if (!validate_opcode(opc, bc)) return MAX_OPCODE;
252 :
253 : // And check it's arguments as far as possible
254 0 : switch (opc)
255 : {
256 : case NOP :
257 : case PUSH_BYTE :
258 : case PUSH_BYTEU :
259 : case PUSH_SHORT :
260 : case PUSH_SHORTU :
261 : case PUSH_LONG :
262 : case ADD :
263 : case SUB :
264 : case MUL :
265 : case DIV :
266 : case MIN_ :
267 : case MAX_ :
268 : case NEG :
269 : case TRUNC8 :
270 : case TRUNC16 :
271 : case COND :
272 : case AND :
273 : case OR :
274 : case NOT :
275 : case EQUAL :
276 : case NOT_EQ :
277 : case LESS :
278 : case GTR :
279 : case LESS_EQ :
280 : case GTR_EQ :
281 0 : break;
282 : case NEXT :
283 : case NEXT_N : // runtime checked
284 : case COPY_NEXT :
285 0 : ++_pre_context;
286 0 : break;
287 : case PUT_GLYPH_8BIT_OBS :
288 0 : valid_upto(_max.classes, bc[0]);
289 0 : break;
290 : case PUT_SUBS_8BIT_OBS :
291 0 : valid_upto(_rule_length, _pre_context + int8(bc[0]));
292 0 : valid_upto(_max.classes, bc[1]);
293 0 : valid_upto(_max.classes, bc[2]);
294 0 : break;
295 : case PUT_COPY :
296 0 : valid_upto(_rule_length, _pre_context + int8(bc[0]));
297 0 : break;
298 : case INSERT :
299 0 : --_pre_context;
300 0 : break;
301 : case DELETE :
302 0 : break;
303 : case ASSOC :
304 0 : for (uint8 num = bc[0]; num; --num)
305 0 : valid_upto(_rule_length, _pre_context + int8(bc[num]));
306 0 : break;
307 : case CNTXT_ITEM :
308 0 : valid_upto(_max.rule_length, _max.pre_context + int8(bc[0]));
309 0 : if (bc + 2 + bc[1] >= _max.bytecode) failure(jump_past_end);
310 0 : break;
311 : case ATTR_SET :
312 : case ATTR_ADD :
313 : case ATTR_SUB :
314 : case ATTR_SET_SLOT :
315 0 : valid_upto(gr_slatMax, bc[0]);
316 0 : break;
317 : case IATTR_SET_SLOT :
318 0 : if (valid_upto(gr_slatMax, bc[0]))
319 0 : valid_upto(_max.attrid[bc[0]], bc[1]);
320 0 : break;
321 : case PUSH_SLOT_ATTR :
322 0 : valid_upto(gr_slatMax, bc[0]);
323 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
324 0 : break;
325 : case PUSH_GLYPH_ATTR_OBS :
326 0 : valid_upto(_max.glyf_attrs, bc[0]);
327 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
328 0 : break;
329 : case PUSH_GLYPH_METRIC :
330 0 : valid_upto(kgmetDescent, bc[0]);
331 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
332 : // level: dp[2] no check necessary
333 0 : break;
334 : case PUSH_FEAT :
335 0 : valid_upto(_max.features, bc[0]);
336 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
337 0 : break;
338 : case PUSH_ATT_TO_GATTR_OBS :
339 0 : valid_upto(_max.glyf_attrs, bc[0]);
340 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
341 0 : break;
342 : case PUSH_ATT_TO_GLYPH_METRIC :
343 0 : valid_upto(kgmetDescent, bc[0]);
344 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
345 : // level: dp[2] no check necessary
346 0 : break;
347 : case PUSH_ISLOT_ATTR :
348 0 : if (valid_upto(gr_slatMax, bc[0]))
349 : {
350 0 : valid_upto(_rule_length, _pre_context + int8(bc[1]));
351 0 : valid_upto(_max.attrid[bc[0]], bc[2]);
352 : }
353 0 : break;
354 : case PUSH_IGLYPH_ATTR :// not implemented
355 : case POP_RET :
356 : case RET_ZERO :
357 : case RET_TRUE :
358 0 : break;
359 : case IATTR_SET :
360 : case IATTR_ADD :
361 : case IATTR_SUB :
362 0 : if (valid_upto(gr_slatMax, bc[0]))
363 0 : valid_upto(_max.attrid[bc[0]], bc[1]);
364 0 : break;
365 : case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
366 : case PUSH_VERSION :
367 0 : break;
368 : case PUT_SUBS :
369 0 : valid_upto(_rule_length, _pre_context + int8(bc[0]));
370 0 : valid_upto(_max.classes, uint16(bc[1]<< 8) | bc[2]);
371 0 : valid_upto(_max.classes, uint16(bc[3]<< 8) | bc[4]);
372 0 : break;
373 : case PUT_SUBS2 : // not implemented
374 : case PUT_SUBS3 : // not implemented
375 0 : break;
376 : case PUT_GLYPH :
377 0 : valid_upto(_max.classes, uint16(bc[0]<< 8) | bc[1]);
378 0 : break;
379 : case PUSH_GLYPH_ATTR :
380 : case PUSH_ATT_TO_GLYPH_ATTR :
381 0 : valid_upto(_max.glyf_attrs, uint16(bc[0]<< 8) | bc[1]);
382 0 : valid_upto(_rule_length, _pre_context + int8(bc[2]));
383 0 : break;
384 : default:
385 0 : failure(invalid_opcode);
386 0 : break;
387 : }
388 :
389 0 : return bool(_code) ? opc : MAX_OPCODE;
390 : }
391 :
392 :
393 0 : void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) throw()
394 : {
395 0 : if (_code._constraint) return;
396 :
397 0 : switch (opc)
398 : {
399 : case DELETE :
400 0 : _code._delete = true;
401 0 : break;
402 : case PUT_GLYPH_8BIT_OBS :
403 : case PUT_GLYPH :
404 0 : _code._modify = true;
405 0 : _analysis.set_changed(_analysis.slotref);
406 0 : break;
407 : case NEXT :
408 : case COPY_NEXT :
409 0 : if (!_analysis.contexts[_analysis.slotref].flags.inserted)
410 0 : ++_analysis.slotref;
411 0 : _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
412 0 : if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
413 0 : break;
414 : case INSERT :
415 0 : _analysis.contexts[_analysis.slotref].flags.inserted = true;
416 0 : _code._modify = true;
417 0 : break;
418 : case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
419 : case PUT_SUBS :
420 0 : _code._modify = true;
421 0 : _analysis.set_changed(_analysis.slotref);
422 : // no break here;
423 : case PUT_COPY :
424 : {
425 0 : if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
426 0 : if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
427 0 : _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
428 0 : else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
429 0 : break;
430 : }
431 : case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
432 0 : if (_code._constraint) return;
433 : case PUSH_GLYPH_ATTR_OBS :
434 : case PUSH_SLOT_ATTR :
435 : case PUSH_GLYPH_METRIC :
436 : case PUSH_ATT_TO_GLYPH_METRIC :
437 : case PUSH_ISLOT_ATTR :
438 : case PUSH_FEAT :
439 0 : if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
440 0 : _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
441 0 : else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
442 0 : break;
443 : case PUSH_ATT_TO_GLYPH_ATTR :
444 0 : if (_code._constraint) return;
445 : case PUSH_GLYPH_ATTR :
446 0 : if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
447 0 : _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
448 0 : else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
449 0 : break;
450 : case ASSOC : // slotrefs in varargs
451 0 : break;
452 : default:
453 0 : break;
454 : }
455 : }
456 :
457 :
458 0 : bool Machine::Code::decoder::emit_opcode(opcode opc, const byte * & bc)
459 : {
460 0 : const opcode_t * op_to_fn = Machine::getOpcodeTable();
461 0 : const opcode_t & op = op_to_fn[opc];
462 0 : if (op.impl[_code._constraint] == 0)
463 : {
464 0 : failure(unimplemented_opcode_used);
465 0 : return false;
466 : }
467 :
468 0 : const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
469 :
470 : // Add this instruction
471 0 : *_instr++ = op.impl[_code._constraint];
472 0 : ++_code._instr_count;
473 :
474 : // Grab the parameters
475 0 : if (param_sz) {
476 0 : memcpy(_data, bc, param_sz * sizeof(byte));
477 0 : bc += param_sz;
478 0 : _data += param_sz;
479 0 : _code._data_size += param_sz;
480 : }
481 :
482 : // recursively decode a context item so we can split the skip into
483 : // instruction and data portions.
484 0 : if (opc == CNTXT_ITEM)
485 : {
486 0 : assert(_pre_context == 0);
487 0 : _pre_context = _max.pre_context + int8(_data[-2]);
488 0 : _rule_length = _max.rule_length;
489 :
490 0 : const size_t ctxt_start = _code._instr_count;
491 0 : byte & instr_skip = _data[-1];
492 0 : byte & data_skip = *_data++;
493 0 : ++_code._data_size;
494 :
495 0 : if (load(bc, bc + instr_skip))
496 : {
497 0 : bc += instr_skip;
498 0 : data_skip = instr_skip - (_code._instr_count - ctxt_start);
499 0 : instr_skip = _code._instr_count - ctxt_start;
500 :
501 0 : _rule_length = 1;
502 0 : _pre_context = 0;
503 : }
504 : }
505 :
506 0 : return bool(_code);
507 : }
508 :
509 :
510 0 : void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end)
511 : {
512 : // insert TEMP_COPY commands for slots that need them (that change and are referenced later)
513 0 : int tempcount = 0;
514 0 : if (_code._constraint) return;
515 :
516 0 : const instr temp_copy = Machine::getOpcodeTable()[TEMP_COPY].impl[0];
517 0 : for (const context * c = _analysis.contexts, * const ce = c + _analysis.slotref; c != ce; ++c)
518 : {
519 0 : if (!c->flags.referenced || !c->flags.changed) continue;
520 :
521 0 : instr * const tip = code + c->codeRef + tempcount;
522 0 : memmove(tip+1, tip, (code_end - tip) * sizeof(instr));
523 0 : *tip = temp_copy;
524 0 : ++code_end;
525 0 : ++tempcount;
526 : }
527 :
528 0 : _code._instr_count = code_end - code;
529 : }
530 :
531 :
532 : inline
533 0 : bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
534 : {
535 0 : if (opc >= MAX_OPCODE)
536 : {
537 0 : failure(invalid_opcode);
538 0 : return false;
539 : }
540 0 : const opcode_t & op = Machine::getOpcodeTable()[opc];
541 0 : const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
542 0 : if (bc + param_sz > _max.bytecode)
543 : {
544 0 : failure(arguments_exhausted);
545 0 : return false;
546 : }
547 0 : return true;
548 : }
549 :
550 :
551 0 : bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
552 : {
553 0 : const bool t = x < limit;
554 0 : if (!t) failure(out_of_range_data);
555 0 : return t;
556 : }
557 :
558 :
559 : inline
560 0 : void Machine::Code::failure(const status_t s) throw() {
561 0 : release_buffers();
562 0 : _status = s;
563 0 : }
564 :
565 :
566 : inline
567 0 : void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
568 0 : contexts[index].flags.referenced = true;
569 0 : if (index > max_ref) max_ref = index;
570 0 : }
571 :
572 :
573 : inline
574 0 : void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
575 0 : contexts[index].flags.changed = true;
576 0 : if (index > max_ref) max_ref = index;
577 0 : }
578 :
579 :
580 0 : void Machine::Code::release_buffers() throw()
581 : {
582 0 : free(_code);
583 0 : free(_data);
584 0 : _code = 0;
585 0 : _data = 0;
586 0 : _own = false;
587 0 : }
588 :
589 :
590 0 : int32 Machine::Code::run(Machine & m, slotref * & map) const
591 : {
592 0 : assert(_own);
593 0 : assert(*this); // Check we are actually runnable
594 :
595 0 : if (m.slotMap().size() <= _max_ref + m.slotMap().context())
596 : {
597 0 : m._status = Machine::slot_offset_out_bounds;
598 : // return (m.slotMap().end() - map);
599 0 : return 1;
600 : }
601 :
602 0 : return m.run(_code, _data, map);
603 : }
604 :
|