Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : *
4 : * Copyright 2016 Mozilla Foundation
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #ifndef wasm_validate_h
20 : #define wasm_validate_h
21 :
22 : #include "wasm/WasmCode.h"
23 : #include "wasm/WasmTypes.h"
24 :
25 : namespace js {
26 : namespace wasm {
27 :
28 : // ModuleEnvironment contains all the state necessary to validate, process or
29 : // render functions. It is created by decoding all the sections before the wasm
30 : // code section and then used immutably during. When compiling a module using a
31 : // ModuleGenerator, the ModuleEnvironment holds state shared between the
32 : // ModuleGenerator thread and background compile threads. All the threads
33 : // are given a read-only view of the ModuleEnvironment, thus preventing race
34 : // conditions.
35 :
36 0 : struct ModuleEnvironment
37 : {
38 : ModuleKind kind;
39 : MemoryUsage memoryUsage;
40 : mozilla::Atomic<uint32_t> minMemoryLength;
41 : Maybe<uint32_t> maxMemoryLength;
42 :
43 : SigWithIdVector sigs;
44 : SigWithIdPtrVector funcSigs;
45 : Uint32Vector funcImportGlobalDataOffsets;
46 : GlobalDescVector globals;
47 : TableDescVector tables;
48 : Uint32Vector asmJSSigToTableIndex;
49 : ImportVector imports;
50 : ExportVector exports;
51 : Maybe<uint32_t> startFuncIndex;
52 : ElemSegmentVector elemSegments;
53 : DataSegmentVector dataSegments;
54 : NameInBytecodeVector funcNames;
55 : CustomSectionVector customSections;
56 :
57 0 : explicit ModuleEnvironment(ModuleKind kind = ModuleKind::Wasm)
58 0 : : kind(kind),
59 : memoryUsage(MemoryUsage::None),
60 0 : minMemoryLength(0)
61 0 : {}
62 :
63 : size_t numTables() const {
64 : return tables.length();
65 : }
66 0 : size_t numSigs() const {
67 0 : return sigs.length();
68 : }
69 0 : size_t numFuncs() const {
70 : // asm.js pre-reserves a bunch of function index space which is
71 : // incrementally filled in during function-body validation. Thus, there
72 : // are a few possible interpretations of numFuncs() (total index space
73 : // size vs. exact number of imports/definitions encountered so far) and
74 : // to simplify things we simply only define this quantity for wasm.
75 0 : MOZ_ASSERT(!isAsmJS());
76 0 : return funcSigs.length();
77 : }
78 0 : size_t numFuncDefs() const {
79 : // asm.js overallocates the length of funcSigs and in general does not
80 : // know the number of function definitions until it's done compiling.
81 0 : MOZ_ASSERT(!isAsmJS());
82 0 : return funcSigs.length() - funcImportGlobalDataOffsets.length();
83 : }
84 0 : size_t numFuncImports() const {
85 0 : MOZ_ASSERT(!isAsmJS());
86 0 : return funcImportGlobalDataOffsets.length();
87 : }
88 0 : bool usesMemory() const {
89 0 : return UsesMemory(memoryUsage);
90 : }
91 0 : bool isAsmJS() const {
92 0 : return kind == ModuleKind::AsmJS;
93 : }
94 0 : bool funcIsImport(uint32_t funcIndex) const {
95 0 : return funcIndex < funcImportGlobalDataOffsets.length();
96 : }
97 0 : uint32_t funcIndexToSigIndex(uint32_t funcIndex) const {
98 0 : return funcSigs[funcIndex] - sigs.begin();
99 : }
100 : };
101 :
102 : typedef UniquePtr<ModuleEnvironment> UniqueModuleEnvironment;
103 :
104 : // The Encoder class appends bytes to the Bytes object it is given during
105 : // construction. The client is responsible for the Bytes's lifetime and must
106 : // keep the Bytes alive as long as the Encoder is used.
107 :
108 : class Encoder
109 : {
110 : Bytes& bytes_;
111 :
112 : template <class T>
113 0 : MOZ_MUST_USE bool write(const T& v) {
114 0 : return bytes_.append(reinterpret_cast<const uint8_t*>(&v), sizeof(T));
115 : }
116 :
117 : template <typename UInt>
118 0 : MOZ_MUST_USE bool writeVarU(UInt i) {
119 0 : do {
120 0 : uint8_t byte = i & 0x7f;
121 0 : i >>= 7;
122 0 : if (i != 0)
123 0 : byte |= 0x80;
124 0 : if (!bytes_.append(byte))
125 0 : return false;
126 0 : } while (i != 0);
127 0 : return true;
128 : }
129 :
130 : template <typename SInt>
131 0 : MOZ_MUST_USE bool writeVarS(SInt i) {
132 : bool done;
133 0 : do {
134 0 : uint8_t byte = i & 0x7f;
135 0 : i >>= 7;
136 0 : done = ((i == 0) && !(byte & 0x40)) || ((i == -1) && (byte & 0x40));
137 0 : if (!done)
138 0 : byte |= 0x80;
139 0 : if (!bytes_.append(byte))
140 0 : return false;
141 0 : } while (!done);
142 0 : return true;
143 : }
144 :
145 0 : void patchVarU32(size_t offset, uint32_t patchBits, uint32_t assertBits) {
146 0 : do {
147 0 : uint8_t assertByte = assertBits & 0x7f;
148 0 : uint8_t patchByte = patchBits & 0x7f;
149 0 : assertBits >>= 7;
150 0 : patchBits >>= 7;
151 0 : if (assertBits != 0) {
152 0 : assertByte |= 0x80;
153 0 : patchByte |= 0x80;
154 : }
155 0 : MOZ_ASSERT(assertByte == bytes_[offset]);
156 0 : bytes_[offset] = patchByte;
157 0 : offset++;
158 0 : } while(assertBits != 0);
159 0 : }
160 :
161 0 : void patchFixedU7(size_t offset, uint8_t patchBits, uint8_t assertBits) {
162 0 : MOZ_ASSERT(patchBits <= uint8_t(INT8_MAX));
163 0 : patchFixedU8(offset, patchBits, assertBits);
164 0 : }
165 :
166 0 : void patchFixedU8(size_t offset, uint8_t patchBits, uint8_t assertBits) {
167 0 : MOZ_ASSERT(bytes_[offset] == assertBits);
168 0 : bytes_[offset] = patchBits;
169 0 : }
170 :
171 0 : uint32_t varU32ByteLength(size_t offset) const {
172 0 : size_t start = offset;
173 0 : while (bytes_[offset] & 0x80)
174 0 : offset++;
175 0 : return offset - start + 1;
176 : }
177 :
178 : public:
179 0 : explicit Encoder(Bytes& bytes)
180 0 : : bytes_(bytes)
181 : {
182 0 : MOZ_ASSERT(empty());
183 0 : }
184 :
185 0 : size_t currentOffset() const { return bytes_.length(); }
186 0 : bool empty() const { return currentOffset() == 0; }
187 :
188 : // Fixed-size encoding operations simply copy the literal bytes (without
189 : // attempting to align).
190 :
191 : MOZ_MUST_USE bool writeFixedU7(uint8_t i) {
192 : MOZ_ASSERT(i <= uint8_t(INT8_MAX));
193 : return writeFixedU8(i);
194 : }
195 0 : MOZ_MUST_USE bool writeFixedU8(uint8_t i) {
196 0 : return write<uint8_t>(i);
197 : }
198 0 : MOZ_MUST_USE bool writeFixedU32(uint32_t i) {
199 0 : return write<uint32_t>(i);
200 : }
201 0 : MOZ_MUST_USE bool writeFixedF32(float f) {
202 0 : return write<float>(f);
203 : }
204 0 : MOZ_MUST_USE bool writeFixedF64(double d) {
205 0 : return write<double>(d);
206 : }
207 0 : MOZ_MUST_USE bool writeFixedI8x16(const I8x16& i8x16) {
208 0 : return write<I8x16>(i8x16);
209 : }
210 0 : MOZ_MUST_USE bool writeFixedI16x8(const I16x8& i16x8) {
211 0 : return write<I16x8>(i16x8);
212 : }
213 0 : MOZ_MUST_USE bool writeFixedI32x4(const I32x4& i32x4) {
214 0 : return write<I32x4>(i32x4);
215 : }
216 0 : MOZ_MUST_USE bool writeFixedF32x4(const F32x4& f32x4) {
217 0 : return write<F32x4>(f32x4);
218 : }
219 :
220 : // Variable-length encodings that all use LEB128.
221 :
222 0 : MOZ_MUST_USE bool writeVarU32(uint32_t i) {
223 0 : return writeVarU<uint32_t>(i);
224 : }
225 0 : MOZ_MUST_USE bool writeVarS32(int32_t i) {
226 0 : return writeVarS<int32_t>(i);
227 : }
228 : MOZ_MUST_USE bool writeVarU64(uint64_t i) {
229 : return writeVarU<uint64_t>(i);
230 : }
231 0 : MOZ_MUST_USE bool writeVarS64(int64_t i) {
232 0 : return writeVarS<int64_t>(i);
233 : }
234 0 : MOZ_MUST_USE bool writeValType(ValType type) {
235 : static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits");
236 0 : MOZ_ASSERT(size_t(type) < size_t(TypeCode::Limit));
237 0 : return writeFixedU8(uint8_t(type));
238 : }
239 0 : MOZ_MUST_USE bool writeBlockType(ExprType type) {
240 : static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits");
241 0 : MOZ_ASSERT(size_t(type) < size_t(TypeCode::Limit));
242 0 : return writeFixedU8(uint8_t(type));
243 : }
244 0 : MOZ_MUST_USE bool writeOp(Op op) {
245 : static_assert(size_t(Op::Limit) == 256, "fits");
246 0 : MOZ_ASSERT(size_t(op) < size_t(Op::Limit));
247 0 : return writeFixedU8(uint8_t(op));
248 : }
249 0 : MOZ_MUST_USE bool writeOp(MozOp op) {
250 : static_assert(size_t(MozOp::Limit) <= 256, "fits");
251 0 : MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit));
252 0 : return writeFixedU8(uint8_t(Op::MozPrefix)) &&
253 0 : writeFixedU8(uint8_t(op));
254 : }
255 :
256 : // Fixed-length encodings that allow back-patching.
257 :
258 0 : MOZ_MUST_USE bool writePatchableFixedU7(size_t* offset) {
259 0 : *offset = bytes_.length();
260 0 : return writeFixedU8(UINT8_MAX);
261 : }
262 0 : void patchFixedU7(size_t offset, uint8_t patchBits) {
263 0 : return patchFixedU7(offset, patchBits, UINT8_MAX);
264 : }
265 :
266 : // Variable-length encodings that allow back-patching.
267 :
268 0 : MOZ_MUST_USE bool writePatchableVarU32(size_t* offset) {
269 0 : *offset = bytes_.length();
270 0 : return writeVarU32(UINT32_MAX);
271 : }
272 0 : void patchVarU32(size_t offset, uint32_t patchBits) {
273 0 : return patchVarU32(offset, patchBits, UINT32_MAX);
274 : }
275 :
276 : // Byte ranges start with an LEB128 length followed by an arbitrary sequence
277 : // of bytes. When used for strings, bytes are to be interpreted as utf8.
278 :
279 0 : MOZ_MUST_USE bool writeBytes(const void* bytes, uint32_t numBytes) {
280 0 : return writeVarU32(numBytes) &&
281 0 : bytes_.append(reinterpret_cast<const uint8_t*>(bytes), numBytes);
282 : }
283 :
284 : // A "section" is a contiguous range of bytes that stores its own size so
285 : // that it may be trivially skipped without examining the contents. Sections
286 : // require backpatching since the size of the section is only known at the
287 : // end while the size's varU32 must be stored at the beginning. Immediately
288 : // after the section length is the string id of the section.
289 :
290 0 : MOZ_MUST_USE bool startSection(SectionId id, size_t* offset) {
291 0 : return writeVarU32(uint32_t(id)) &&
292 0 : writePatchableVarU32(offset);
293 : }
294 0 : void finishSection(size_t offset) {
295 0 : return patchVarU32(offset, bytes_.length() - offset - varU32ByteLength(offset));
296 : }
297 : };
298 :
299 : // The Decoder class decodes the bytes in the range it is given during
300 : // construction. The client is responsible for keeping the byte range alive as
301 : // long as the Decoder is used.
302 :
303 : class Decoder
304 : {
305 : const uint8_t* const beg_;
306 : const uint8_t* const end_;
307 : const uint8_t* cur_;
308 : const size_t offsetInModule_;
309 : UniqueChars* error_;
310 : bool resilientMode_;
311 :
312 : template <class T>
313 0 : MOZ_MUST_USE bool read(T* out) {
314 0 : if (bytesRemain() < sizeof(T))
315 0 : return false;
316 0 : memcpy((void*)out, cur_, sizeof(T));
317 0 : cur_ += sizeof(T);
318 0 : return true;
319 : }
320 :
321 : template <class T>
322 : T uncheckedRead() {
323 : MOZ_ASSERT(bytesRemain() >= sizeof(T));
324 : T ret;
325 : memcpy(&ret, cur_, sizeof(T));
326 : cur_ += sizeof(T);
327 : return ret;
328 : }
329 :
330 : template <class T>
331 : void uncheckedRead(T* ret) {
332 : MOZ_ASSERT(bytesRemain() >= sizeof(T));
333 : memcpy(ret, cur_, sizeof(T));
334 : cur_ += sizeof(T);
335 : }
336 :
337 : template <typename UInt>
338 0 : MOZ_MUST_USE bool readVarU(UInt* out) {
339 0 : const unsigned numBits = sizeof(UInt) * CHAR_BIT;
340 0 : const unsigned remainderBits = numBits % 7;
341 0 : const unsigned numBitsInSevens = numBits - remainderBits;
342 0 : UInt u = 0;
343 : uint8_t byte;
344 0 : UInt shift = 0;
345 0 : do {
346 0 : if (!readFixedU8(&byte))
347 0 : return false;
348 0 : if (!(byte & 0x80)) {
349 0 : *out = u | UInt(byte) << shift;
350 0 : return true;
351 : }
352 0 : u |= UInt(byte & 0x7F) << shift;
353 0 : shift += 7;
354 0 : } while (shift != numBitsInSevens);
355 0 : if (!readFixedU8(&byte) || (byte & (unsigned(-1) << remainderBits)))
356 0 : return false;
357 0 : *out = u | (UInt(byte) << numBitsInSevens);
358 0 : return true;
359 : }
360 :
361 : template <typename SInt>
362 0 : MOZ_MUST_USE bool readVarS(SInt* out) {
363 0 : const unsigned numBits = sizeof(SInt) * CHAR_BIT;
364 0 : const unsigned remainderBits = numBits % 7;
365 0 : const unsigned numBitsInSevens = numBits - remainderBits;
366 0 : SInt s = 0;
367 : uint8_t byte;
368 0 : unsigned shift = 0;
369 0 : do {
370 0 : if (!readFixedU8(&byte))
371 0 : return false;
372 0 : s |= SInt(byte & 0x7f) << shift;
373 0 : shift += 7;
374 0 : if (!(byte & 0x80)) {
375 0 : if (byte & 0x40)
376 0 : s |= SInt(-1) << shift;
377 0 : *out = s;
378 0 : return true;
379 : }
380 0 : } while (shift < numBitsInSevens);
381 0 : if (!remainderBits || !readFixedU8(&byte) || (byte & 0x80))
382 0 : return false;
383 0 : uint8_t mask = 0x7f & (uint8_t(-1) << remainderBits);
384 0 : if ((byte & mask) != ((byte & (1 << (remainderBits - 1))) ? mask : 0))
385 0 : return false;
386 0 : *out = s | SInt(byte) << shift;
387 0 : return true;
388 : }
389 :
390 : public:
391 0 : Decoder(const uint8_t* begin, const uint8_t* end, size_t offsetInModule, UniqueChars* error,
392 : bool resilientMode = false)
393 0 : : beg_(begin),
394 : end_(end),
395 : cur_(begin),
396 : offsetInModule_(offsetInModule),
397 : error_(error),
398 0 : resilientMode_(resilientMode)
399 : {
400 0 : MOZ_ASSERT(begin <= end);
401 0 : }
402 0 : explicit Decoder(const Bytes& bytes, UniqueChars* error = nullptr)
403 0 : : beg_(bytes.begin()),
404 0 : end_(bytes.end()),
405 0 : cur_(bytes.begin()),
406 : offsetInModule_(0),
407 : error_(error),
408 0 : resilientMode_(false)
409 0 : {}
410 :
411 : // These convenience functions use currentOffset() as the errorOffset.
412 0 : bool fail(const char* msg) { return fail(currentOffset(), msg); }
413 : bool failf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3);
414 :
415 : // Report an error at the given offset (relative to the whole module).
416 : bool fail(size_t errorOffset, const char* msg);
417 :
418 0 : void clearError() {
419 0 : if (error_)
420 0 : error_->reset();
421 0 : }
422 :
423 0 : bool done() const {
424 0 : MOZ_ASSERT(cur_ <= end_);
425 0 : return cur_ == end_;
426 : }
427 0 : bool resilientMode() const {
428 0 : return resilientMode_;
429 : }
430 :
431 0 : size_t bytesRemain() const {
432 0 : MOZ_ASSERT(end_ >= cur_);
433 0 : return size_t(end_ - cur_);
434 : }
435 : // pos must be a value previously returned from currentPosition.
436 0 : void rollbackPosition(const uint8_t* pos) {
437 0 : cur_ = pos;
438 0 : }
439 0 : const uint8_t* currentPosition() const {
440 0 : return cur_;
441 : }
442 0 : size_t currentOffset() const {
443 0 : return offsetInModule_ + (cur_ - beg_);
444 : }
445 0 : const uint8_t* begin() const {
446 0 : return beg_;
447 : }
448 0 : const uint8_t* end() const {
449 0 : return end_;
450 : }
451 :
452 : // Fixed-size encoding operations simply copy the literal bytes (without
453 : // attempting to align).
454 :
455 0 : MOZ_MUST_USE bool readFixedU8(uint8_t* i) {
456 0 : return read<uint8_t>(i);
457 : }
458 0 : MOZ_MUST_USE bool readFixedU32(uint32_t* u) {
459 0 : return read<uint32_t>(u);
460 : }
461 0 : MOZ_MUST_USE bool readFixedF32(float* f) {
462 0 : return read<float>(f);
463 : }
464 0 : MOZ_MUST_USE bool readFixedF64(double* d) {
465 0 : return read<double>(d);
466 : }
467 0 : MOZ_MUST_USE bool readFixedI8x16(I8x16* i8x16) {
468 0 : return read<I8x16>(i8x16);
469 : }
470 0 : MOZ_MUST_USE bool readFixedI16x8(I16x8* i16x8) {
471 0 : return read<I16x8>(i16x8);
472 : }
473 0 : MOZ_MUST_USE bool readFixedI32x4(I32x4* i32x4) {
474 0 : return read<I32x4>(i32x4);
475 : }
476 0 : MOZ_MUST_USE bool readFixedF32x4(F32x4* f32x4) {
477 0 : return read<F32x4>(f32x4);
478 : }
479 :
480 : // Variable-length encodings that all use LEB128.
481 :
482 0 : MOZ_MUST_USE bool readVarU32(uint32_t* out) {
483 0 : return readVarU<uint32_t>(out);
484 : }
485 0 : MOZ_MUST_USE bool readVarS32(int32_t* out) {
486 0 : return readVarS<int32_t>(out);
487 : }
488 : MOZ_MUST_USE bool readVarU64(uint64_t* out) {
489 : return readVarU<uint64_t>(out);
490 : }
491 0 : MOZ_MUST_USE bool readVarS64(int64_t* out) {
492 0 : return readVarS<int64_t>(out);
493 : }
494 0 : MOZ_MUST_USE bool readValType(uint8_t* type) {
495 : static_assert(uint8_t(TypeCode::Limit) <= UINT8_MAX, "fits");
496 0 : return readFixedU8(type);
497 : }
498 0 : MOZ_MUST_USE bool readBlockType(uint8_t* type) {
499 : static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits");
500 0 : return readFixedU8(type);
501 : }
502 0 : MOZ_MUST_USE bool readOp(OpBytes* op) {
503 : static_assert(size_t(Op::Limit) == 256, "fits");
504 : uint8_t u8;
505 0 : if (!readFixedU8(&u8))
506 0 : return false;
507 0 : op->b0 = u8;
508 0 : if (MOZ_LIKELY(!IsPrefixByte(u8)))
509 0 : return true;
510 0 : if (!readFixedU8(&u8)) {
511 0 : op->b1 = 0; // Make it sane
512 0 : return false;
513 : }
514 0 : op->b1 = u8;
515 0 : return true;
516 : }
517 :
518 : // See writeBytes comment.
519 :
520 0 : MOZ_MUST_USE bool readBytes(uint32_t numBytes, const uint8_t** bytes = nullptr) {
521 0 : if (bytes)
522 0 : *bytes = cur_;
523 0 : if (bytesRemain() < numBytes)
524 0 : return false;
525 0 : cur_ += numBytes;
526 0 : return true;
527 : }
528 :
529 : // See "section" description in Encoder.
530 :
531 : static const uint32_t NotStarted = UINT32_MAX;
532 :
533 : MOZ_MUST_USE bool startSection(SectionId id,
534 : ModuleEnvironment* env,
535 : uint32_t* sectionStart,
536 : uint32_t* sectionSize,
537 : const char* sectionName);
538 : MOZ_MUST_USE bool finishSection(uint32_t sectionStart,
539 : uint32_t sectionSize,
540 : const char* sectionName);
541 :
542 : // Custom sections do not cause validation errors unless the error is in
543 : // the section header itself.
544 :
545 : MOZ_MUST_USE bool startCustomSection(const char* expected,
546 : size_t expectedLength,
547 : ModuleEnvironment* env,
548 : uint32_t* sectionStart,
549 : uint32_t* sectionSize);
550 : template <size_t NameSizeWith0>
551 0 : MOZ_MUST_USE bool startCustomSection(const char (&name)[NameSizeWith0],
552 : ModuleEnvironment* env,
553 : uint32_t* sectionStart,
554 : uint32_t* sectionSize)
555 : {
556 0 : MOZ_ASSERT(name[NameSizeWith0 - 1] == '\0');
557 0 : return startCustomSection(name, NameSizeWith0 - 1, env, sectionStart, sectionSize);
558 : }
559 : void finishCustomSection(uint32_t sectionStart, uint32_t sectionSize);
560 : MOZ_MUST_USE bool skipCustomSection(ModuleEnvironment* env);
561 :
562 : // The Name section has its own subsections. Like startSection, NotStart is
563 : // returned as the endOffset if the given name subsection wasn't present.
564 :
565 : MOZ_MUST_USE bool startNameSubsection(NameType nameType, uint32_t* endOffset);
566 : MOZ_MUST_USE bool finishNameSubsection(uint32_t endOffset);
567 :
568 : // The infallible "unchecked" decoding functions can be used when we are
569 : // sure that the bytes are well-formed (by construction or due to previous
570 : // validation).
571 :
572 : uint8_t uncheckedReadFixedU8() {
573 : return uncheckedRead<uint8_t>();
574 : }
575 : uint32_t uncheckedReadFixedU32() {
576 : return uncheckedRead<uint32_t>();
577 : }
578 : void uncheckedReadFixedF32(float* out) {
579 : uncheckedRead<float>(out);
580 : }
581 : void uncheckedReadFixedF64(double* out) {
582 : uncheckedRead<double>(out);
583 : }
584 : template <typename UInt>
585 : UInt uncheckedReadVarU() {
586 : static const unsigned numBits = sizeof(UInt) * CHAR_BIT;
587 : static const unsigned remainderBits = numBits % 7;
588 : static const unsigned numBitsInSevens = numBits - remainderBits;
589 : UInt decoded = 0;
590 : uint32_t shift = 0;
591 : do {
592 : uint8_t byte = *cur_++;
593 : if (!(byte & 0x80))
594 : return decoded | (UInt(byte) << shift);
595 : decoded |= UInt(byte & 0x7f) << shift;
596 : shift += 7;
597 : } while (shift != numBitsInSevens);
598 : uint8_t byte = *cur_++;
599 : MOZ_ASSERT(!(byte & 0xf0));
600 : return decoded | (UInt(byte) << numBitsInSevens);
601 : }
602 : uint32_t uncheckedReadVarU32() {
603 : return uncheckedReadVarU<uint32_t>();
604 : }
605 : int32_t uncheckedReadVarS32() {
606 : int32_t i32 = 0;
607 : MOZ_ALWAYS_TRUE(readVarS32(&i32));
608 : return i32;
609 : }
610 : uint64_t uncheckedReadVarU64() {
611 : return uncheckedReadVarU<uint64_t>();
612 : }
613 : int64_t uncheckedReadVarS64() {
614 : int64_t i64 = 0;
615 : MOZ_ALWAYS_TRUE(readVarS64(&i64));
616 : return i64;
617 : }
618 : ValType uncheckedReadValType() {
619 : return (ValType)uncheckedReadFixedU8();
620 : }
621 : Op uncheckedReadOp() {
622 : static_assert(size_t(Op::Limit) == 256, "fits");
623 : uint8_t u8 = uncheckedReadFixedU8();
624 : return u8 != UINT8_MAX
625 : ? Op(u8)
626 : : Op(uncheckedReadFixedU8() + UINT8_MAX);
627 : }
628 : void uncheckedReadFixedI8x16(I8x16* i8x16) {
629 : struct T { I8x16 v; };
630 : T t = uncheckedRead<T>();
631 : memcpy(i8x16, &t, sizeof(t));
632 : }
633 : void uncheckedReadFixedI16x8(I16x8* i16x8) {
634 : struct T { I16x8 v; };
635 : T t = uncheckedRead<T>();
636 : memcpy(i16x8, &t, sizeof(t));
637 : }
638 : void uncheckedReadFixedI32x4(I32x4* i32x4) {
639 : struct T { I32x4 v; };
640 : T t = uncheckedRead<T>();
641 : memcpy(i32x4, &t, sizeof(t));
642 : }
643 : void uncheckedReadFixedF32x4(F32x4* f32x4) {
644 : struct T { F32x4 v; };
645 : T t = uncheckedRead<T>();
646 : memcpy(f32x4, &t, sizeof(t));
647 : }
648 : };
649 :
650 : // The local entries are part of function bodies and thus serialized by both
651 : // wasm and asm.js and decoded as part of both validation and compilation.
652 :
653 : MOZ_MUST_USE bool
654 : EncodeLocalEntries(Encoder& d, const ValTypeVector& locals);
655 :
656 : MOZ_MUST_USE bool
657 : DecodeLocalEntries(Decoder& d, ModuleKind kind, ValTypeVector* locals);
658 :
659 : // Calling DecodeModuleEnvironment decodes all sections up to the code section
660 : // and performs full validation of all those sections. The client must then
661 : // decode the code section itself, reusing ValidateFunctionBody if necessary,
662 : // and finally call DecodeModuleTail to decode all remaining sections after the
663 : // code section (again, performing full validation).
664 :
665 : MOZ_MUST_USE bool
666 : DecodeModuleEnvironment(Decoder& d, ModuleEnvironment* env);
667 :
668 : MOZ_MUST_USE bool
669 : ValidateFunctionBody(const ModuleEnvironment& env, uint32_t funcIndex, uint32_t bodySize,
670 : Decoder& d);
671 :
672 : MOZ_MUST_USE bool
673 : DecodeModuleTail(Decoder& d, ModuleEnvironment* env);
674 :
675 : // Validate an entire module, returning true if the module was validated
676 : // successfully. If Validate returns false:
677 : // - if *error is null, the caller should report out-of-memory
678 : // - otherwise, there was a legitimate error described by *error
679 :
680 : MOZ_MUST_USE bool
681 : Validate(const ShareableBytes& bytecode, UniqueChars* error);
682 :
683 : } // namespace wasm
684 : } // namespace js
685 :
686 : #endif // namespace wasm_validate_h
|