LCOV - code coverage report
Current view: top level - js/src/wasm - WasmValidate.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 264 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 89 0.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13