tor-browser

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

WasmValidate.h (8302B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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 "js/Utility.h"
     23 #include "js/WasmFeatures.h"
     24 
     25 #include "wasm/WasmBinary.h"
     26 #include "wasm/WasmCompile.h"
     27 #include "wasm/WasmCompileArgs.h"
     28 #include "wasm/WasmModuleTypes.h"
     29 #include "wasm/WasmOpIter.h"
     30 #include "wasm/WasmProcess.h"
     31 #include "wasm/WasmTypeDef.h"
     32 
     33 namespace js {
     34 namespace wasm {
     35 
     36 // ElemSegmentFlags provides methods for decoding and encoding the flags field
     37 // of an element segment. This is needed as the flags field has a non-trivial
     38 // encoding that is effectively split into independent `kind` and `payload`
     39 // enums.
     40 class ElemSegmentFlags {
     41  enum class Flags : uint32_t {
     42    // 0 means active. 1 means (passive or declared), disambiguated by the next
     43    // bit.
     44    Passive = 0x1,
     45    // For active segments, 1 means a table index is present. Otherwise, 0 means
     46    // passive and 1 means declared.
     47    TableIndexOrDeclared = 0x2,
     48    // 0 means element kind / index (currently only func indexes). 1 means
     49    // element ref type and initializer expressions.
     50    ElemExpressions = 0x4,
     51 
     52    // Below this line are convenient combinations of flags
     53    KindMask = Passive | TableIndexOrDeclared,
     54    PayloadMask = ElemExpressions,
     55    AllFlags = Passive | TableIndexOrDeclared | ElemExpressions,
     56  };
     57  uint32_t encoded_;
     58 
     59  explicit ElemSegmentFlags(uint32_t encoded) : encoded_(encoded) {}
     60 
     61 public:
     62  ElemSegmentFlags(ElemSegmentKind kind, ElemSegmentPayload payload) {
     63    encoded_ = uint32_t(kind) | uint32_t(payload);
     64  }
     65 
     66  static mozilla::Maybe<ElemSegmentFlags> construct(uint32_t encoded) {
     67    if (encoded > uint32_t(Flags::AllFlags)) {
     68      return mozilla::Nothing();
     69    }
     70    return mozilla::Some(ElemSegmentFlags(encoded));
     71  }
     72 
     73  uint32_t encoded() const { return encoded_; }
     74 
     75  ElemSegmentKind kind() const {
     76    return static_cast<ElemSegmentKind>(encoded_ & uint32_t(Flags::KindMask));
     77  }
     78  ElemSegmentPayload payload() const {
     79    return static_cast<ElemSegmentPayload>(encoded_ &
     80                                           uint32_t(Flags::PayloadMask));
     81  }
     82 };
     83 
     84 // OpIter specialized for validation.
     85 
     86 class NothingVector {
     87  mozilla::Nothing unused_;
     88 
     89 public:
     90  bool reserve(size_t size) { return true; }
     91  bool resize(size_t length) { return true; }
     92  mozilla::Nothing& operator[](size_t) { return unused_; }
     93  mozilla::Nothing& back() { return unused_; }
     94  size_t length() const { return 0; }
     95  bool append(mozilla::Nothing& nothing) { return true; }
     96  void infallibleAppend(mozilla::Nothing& nothing) {}
     97 };
     98 
     99 struct ValidatingPolicy {
    100  using Value = mozilla::Nothing;
    101  using ValueVector = NothingVector;
    102  using ControlItem = mozilla::Nothing;
    103 };
    104 
    105 template <typename Policy>
    106 class OpIter;
    107 
    108 using ValidatingOpIter = OpIter<ValidatingPolicy>;
    109 
    110 // Shared subtyping function across validation.
    111 
    112 [[nodiscard]] bool CheckIsSubtypeOf(Decoder& d, const CodeMetadata& codeMeta,
    113                                    size_t opcodeOffset, ResultType subType,
    114                                    ResultType superType);
    115 [[nodiscard]] bool CheckIsSubtypeOf(Decoder& d, const CodeMetadata& codeMeta,
    116                                    size_t opcodeOffset, StorageType subType,
    117                                    StorageType superType);
    118 
    119 // The local entries are part of function bodies and thus serialized by both
    120 // wasm and asm.js and decoded as part of both validation and compilation.
    121 
    122 [[nodiscard]] bool EncodeLocalEntries(Encoder& e, const ValTypeVector& locals);
    123 
    124 // This performs no validation; the local entries must already have been
    125 // validated by an earlier pass.
    126 
    127 [[nodiscard]] bool DecodeValidatedLocalEntries(const TypeContext& types,
    128                                               Decoder& d,
    129                                               ValTypeVector* locals);
    130 
    131 // This validates the entries. Function params are inserted before the locals
    132 // to generate the full local entries for use in validation
    133 
    134 [[nodiscard]] bool DecodeLocalEntriesWithParams(Decoder& d,
    135                                                const CodeMetadata& codeMeta,
    136                                                uint32_t funcIndex,
    137                                                ValTypeVector* locals);
    138 
    139 // Returns whether the given [begin, end) prefix of a module's bytecode starts a
    140 // code section and, if so, returns the BytecodeRange of that code section.
    141 // Note that, even if this function returns 'false', [begin, end) may actually
    142 // be a valid module in the special case when there are no function defs and the
    143 // code section is not present. Such modules can be valid so the caller must
    144 // handle this special case.
    145 
    146 [[nodiscard]] bool StartsCodeSection(const uint8_t* begin, const uint8_t* end,
    147                                     BytecodeRange* codeSection);
    148 
    149 // Calling DecodeModuleEnvironment decodes all sections up to the code section
    150 // and performs full validation of all those sections. The client must then
    151 // decode the code section itself, reusing ValidateFunctionBody if necessary,
    152 // and finally call DecodeModuleTail to decode all remaining sections after the
    153 // code section (again, performing full validation).
    154 
    155 [[nodiscard]] bool DecodeModuleEnvironment(Decoder& d, CodeMetadata* codeMeta,
    156                                           ModuleMetadata* moduleMeta);
    157 
    158 [[nodiscard]] bool ValidateFunctionBody(const CodeMetadata& codeMeta,
    159                                        uint32_t funcIndex, uint32_t bodySize,
    160                                        Decoder& d);
    161 
    162 [[nodiscard]] bool DecodeModuleTail(Decoder& d, CodeMetadata* codeMeta,
    163                                    ModuleMetadata* meta);
    164 
    165 // Validate an entire module, returning true if the module was validated
    166 // successfully. If Validate returns false:
    167 //  - if *error is null, the caller should report out-of-memory
    168 //  - otherwise, there was a legitimate error described by *error
    169 
    170 [[nodiscard]] bool Validate(JSContext* cx, const BytecodeSource& bytecode,
    171                            const FeatureOptions& options, UniqueChars* error);
    172 
    173 struct NopOpDumper {
    174  void dumpOpBegin(OpBytes op) {}
    175  void dumpOpEnd() {}
    176  void dumpTypeIndex(uint32_t typeIndex, bool asTypeUse = false) {}
    177  void dumpFuncIndex(uint32_t funcIndex) {}
    178  void dumpTableIndex(uint32_t tableIndex) {}
    179  void dumpGlobalIndex(uint32_t globalIndex) {}
    180  void dumpMemoryIndex(uint32_t memoryIndex) {}
    181  void dumpElemIndex(uint32_t elemIndex) {}
    182  void dumpDataIndex(uint32_t dataIndex) {}
    183  void dumpTagIndex(uint32_t tagIndex) {}
    184  void dumpLocalIndex(uint32_t localIndex) {}
    185  void dumpBlockType(BlockType type) {}
    186  void dumpI32Const(int32_t constant) {}
    187  void dumpI64Const(int64_t constant) {}
    188  void dumpF32Const(float constant) {}
    189  void dumpF64Const(double constant) {}
    190  void dumpV128Const(V128 constant) {}
    191  void dumpVectorMask(V128 mask) {}
    192  void dumpRefType(RefType type) {}
    193  void dumpHeapType(RefType type) {}
    194  void dumpValType(ValType type) {}
    195  void dumpTryTableCatches(const TryTableCatchVector& catches) {}
    196  void dumpLinearMemoryAddress(LinearMemoryAddress<mozilla::Nothing> addr) {}
    197  void dumpBlockDepth(uint32_t relativeDepth) {}
    198  void dumpBlockDepths(const Uint32Vector& relativeDepths) {}
    199  void dumpFieldIndex(uint32_t fieldIndex) {}
    200  void dumpNumElements(uint32_t numElements) {}
    201  void dumpLaneIndex(uint32_t laneIndex) {}
    202 
    203  void startScope() {};
    204  void endScope() {};
    205 };
    206 
    207 template <class T>
    208 [[nodiscard]] bool ValidateOps(ValidatingOpIter& iter, T& dumper,
    209                               const CodeMetadata& codeMeta);
    210 
    211 }  // namespace wasm
    212 }  // namespace js
    213 
    214 #endif  // namespace wasm_validate_h