diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 27aac4b31..96fa6b2fc 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -323,7 +323,7 @@ Tables .. _embed-table-alloc: -:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +:math:`\F{table\_alloc}(\store, \tabletype, \reff) : (\store, \tableaddr)` .......................................................................... 1. Pre-condition: :math:`\tabletype` is :ref:`valid `. diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index 2503a7ab0..c3ffc2a32 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -431,8 +431,8 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\V128.\STORE\K{16\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{59}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\STORE\K{32\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5A}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), Instruction(r'\V128.\STORE\K{64\_lane}~\memarg~\laneidx', r'\hex{FD}~~\hex{5B}', r'[\I32~\V128] \to []', r'valid-store-lane', r'exec-store-lane'), - Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), - Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg~\laneidx', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\LOAD\K{32\_zero}~\memarg', r'\hex{FD}~~\hex{5C}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), + Instruction(r'\V128.\LOAD\K{64\_zero}~\memarg', r'\hex{FD}~~\hex{5D}', r'[\I32] \to [\V128]', r'valid-load-zero', r'exec-load-zero'), Instruction(r'\F32X4.\VDEMOTE\K{\_f64x2\_zero}', r'\hex{FD}~~\hex{5E}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-demote'), Instruction(r'\F64X2.\VPROMOTE\K{\_low\_f32x4}', r'\hex{FD}~~\hex{5F}', r'[\V128] \to [\V128]', r'valid-vcvtop', r'exec-vcvtop', r'op-promote'), Instruction(r'\I8X16.\VABS', r'\hex{FD}~~\hex{60}', r'[\V128] \to [\V128]', r'valid-vunop', r'exec-vunop', r'op-iabs'), diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index b179a9ff1..29a06a904 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -257,8 +257,8 @@ Module instances are classified by *module contexts*, which are regular :ref:`co .. index:: element instance, reference .. _valid-eleminst: -:ref:`Element Instances ` :math:`\{ \EIELEM~\X{fa}^\ast \}` -............................................................................ +:ref:`Element Instances ` :math:`\{ \EITYPE~t, \EIELEM~\reff^\ast \}` +...................................................................................... * For each :ref:`reference ` :math:`\reff_i` in the elements :math:`\reff^n`: diff --git a/document/core/binary/conventions.rst b/document/core/binary/conventions.rst index 83c80399f..7b606e1e4 100644 --- a/document/core/binary/conventions.rst +++ b/document/core/binary/conventions.rst @@ -54,6 +54,7 @@ In order to distinguish symbols of the binary syntax from symbols of the abstrac (This is a shorthand for :math:`B^n` where :math:`n \leq 1`.) * :math:`x{:}B` denotes the same language as the nonterminal :math:`B`, but also binds the variable :math:`x` to the attribute synthesized for :math:`B`. + A pattern may also be used instead of a variable, e.g., :math:`7{:}B`. * Productions are written :math:`\B{sym} ::= B_1 \Rightarrow A_1 ~|~ \dots ~|~ B_n \Rightarrow A_n`, where each :math:`A_i` is the attribute that is synthesized for :math:`\B{sym}` in the given case, usually from attribute variables bound in :math:`B_i`. diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index e9c72b61a..8e488582d 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -60,7 +60,7 @@ Each section consists of * a one-byte section *id*, * the |U32| *size* of the contents, in bytes, -* the actual *contents*, whose structure is depended on the section id. +* the actual *contents*, whose structure is dependent on the section id. Every section is optional; an omitted section is equivalent to the section being present with empty contents. diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 18bfc522e..4a3d66d45 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -20,8 +20,9 @@ The mapping of numeric instructions to their underlying operators is expressed b .. math:: \begin{array}{lll@{\qquad}l} - \X{op}_{\K{i}N}(n_1,\dots,n_k) &=& \F{i}\X{op}_N(n_1,\dots,n_k) \\ - \X{op}_{\K{f}N}(z_1,\dots,z_k) &=& \F{f}\X{op}_N(z_1,\dots,z_k) \\ + \X{op}_{\IN}(i_1,\dots,i_k) &=& \F{i}\X{op}_N(i_1,\dots,i_k) \\ + \X{op}_{\FN}(z_1,\dots,z_k) &=& \F{f}\X{op}_N(z_1,\dots,z_k) \\ + \X{op}_{\VN}(i_1,\dots,i_k) &=& \F{i}\X{op}_N(i_1,\dots,i_k) \\ \end{array} And for :ref:`conversion operators `: @@ -292,14 +293,14 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -3. Let :math:`c` be the result of computing :math:`\vvunop_{\I128}(c_1)`. +3. Let :math:`c` be the result of computing :math:`\vvunop_{\V128}(c_1)`. 4. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{lcl@{\qquad}l} (\V128\K{.}\VCONST~c_1)~\V128\K{.}\vvunop &\stepto& (\V128\K{.}\VCONST~c) - & (\iff c = \vvunop_{\I128}(c_1)) \\ + & (\iff c = \vvunop_{\V128}(c_1)) \\ \end{array} @@ -314,14 +315,14 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -4. Let :math:`c` be the result of computing :math:`\vvbinop_{\I128}(c_1, c_2)`. +4. Let :math:`c` be the result of computing :math:`\vvbinop_{\V128}(c_1, c_2)`. 5. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{lcl@{\qquad}l} (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~\V128\K{.}\vvbinop &\stepto& (\V128\K{.}\VCONST~c) - & (\iff c = \vvbinop_{\I128}(c_1, c_2)) \\ + & (\iff c = \vvbinop_{\V128}(c_1, c_2)) \\ \end{array} @@ -338,14 +339,14 @@ Most vector instructions are defined in terms of generic numeric operators appli 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`c` be the result of computing :math:`\vvternop_{\I128}(c_1, c_2, c_3)`. +5. Let :math:`c` be the result of computing :math:`\vvternop_{\V128}(c_1, c_2, c_3)`. 6. Push the value :math:`\V128.\VCONST~c` to the stack. .. math:: \begin{array}{lcl@{\qquad}l} (\V128\K{.}\VCONST~c_1)~(\V128\K{.}\VCONST~c_2)~(\V128\K{.}\VCONST~c_3)~\V128\K{.}\vvternop &\stepto& (\V128\K{.}\VCONST~c) - & (\iff c = \vvternop_{\I128}(c_1, c_2, c_3)) \\ + & (\iff c = \vvternop_{\V128}(c_1, c_2, c_3)) \\ \end{array} @@ -379,15 +380,15 @@ Most vector instructions are defined in terms of generic numeric operators appli 2. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -3. Let :math:`i^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. +3. Let :math:`i^\ast` be the result of computing :math:`\lanes_{\I8X16}(c_2)`. 4. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -5. Let :math:`j^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. +5. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\I8X16}(c_1)`. 6. Let :math:`c^\ast` be the concatenation of the two sequences :math:`j^\ast` and :math:`0^{240}`. -7. Let :math:`c'` be the result of computing :math:`\lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. +7. Let :math:`c'` be the result of computing :math:`\lanes^{-1}_{\I8X16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])`. 8. Push the value :math:`\V128.\VCONST~c'` onto the stack. @@ -398,9 +399,9 @@ Most vector instructions are defined in terms of generic numeric operators appli \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & i^\ast = \lanes_{i8x16}(c_2) \\ - \wedge & c^\ast = \lanes_{i8x16}(c_1)~0^{240} \\ - \wedge & c' = \lanes^{-1}_{i8x16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])) + (\iff & i^\ast = \lanes_{\I8X16}(c_2) \\ + \wedge & c^\ast = \lanes_{\I8X16}(c_1)~0^{240} \\ + \wedge & c' = \lanes^{-1}_{\I8X16}(c^\ast[ i^\ast[0] ] \dots c^\ast[ i^\ast[15] ])) \end{array} \end{array} @@ -416,15 +417,15 @@ Most vector instructions are defined in terms of generic numeric operators appli 3. Pop the value :math:`\V128.\VCONST~c_2` from the stack. -4. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{i8x16}(c_2)`. +4. Let :math:`i_2^\ast` be the result of computing :math:`\lanes_{\I8X16}(c_2)`. 5. Pop the value :math:`\V128.\VCONST~c_1` from the stack. -6. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{i8x16}(c_1)`. +6. Let :math:`i_1^\ast` be the result of computing :math:`\lanes_{\I8X16}(c_1)`. 7. Let :math:`i^\ast` be the concatenation of the two sequences :math:`i_1^\ast` and :math:`i_2^\ast`. -8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. +8. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\I8X16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])`. 9. Push the value :math:`\V128.\VCONST~c` onto the stack. @@ -435,8 +436,8 @@ Most vector instructions are defined in terms of generic numeric operators appli \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & i^\ast = \lanes_{i8x16}(c_1)~\lanes_{i8x16}(c_2) \\ - \wedge & c = \lanes^{-1}_{i8x16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])) + (\iff & i^\ast = \lanes_{\I8X16}(c_1)~\lanes_{\I8X16}(c_2) \\ + \wedge & c = \lanes^{-1}_{\I8X16}(i^\ast[x^\ast[0]] \dots i^\ast[x^\ast[15]])) \end{array} \end{array} @@ -1681,7 +1682,7 @@ Table Instructions 4. Assert: due to :ref:`validation `, :math:`S.\SELEMS[a]` exists. -5. Replace :math:`S.\SELEMS[a]` with the :ref:`element instance ` :math:`\{\EIELEM~\epsilon\}`. +5. Replace :math:`S.\SELEMS[a].\EIELEM` with :math:`\epsilon`. .. math:: ~\\[-1ex] @@ -1690,7 +1691,7 @@ Table Instructions S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - (\iff S' = S \with \SELEMS[F.\AMODULE.\MIELEMS[x]] = \{ \EIELEM~\epsilon \}) \\ + (\iff S' = S \with \SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM = \epsilon) \\ \end{array} @@ -1875,7 +1876,7 @@ Memory Instructions 14. Let :math:`n_k` be the result of computing :math:`\extend^{\sx}_{M,W}(m_k)`. -15. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\X{i}W\K{x}N}(n_0 \dots n_{N-1})`. +15. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}W\K{x}N}(n_0 \dots n_{N-1})`. 16. Push the value :math:`\V128.\CONST~c` to the stack. @@ -1891,7 +1892,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\UNSHARED \\ \wedge & \X{ea} + M \cdot N / 8 \leq |\X{mem}.\MIDATA| \\ \wedge & \bytes_{\iM}(m_k) = \X{mem}.\MIDATA[\X{ea} + k \cdot M/8 \slice M/8] \\ - \wedge & c = \lanes^{-1}_{\X{i}W\K{x}N}(\extend^{\sx}_{M,W}(m_0) \dots \extend^{\sx}_{M,W}(m_{N-1}))) \\[1ex] + \wedge & c = \lanes^{-1}_{\K{i}W\K{x}N}(\extend^{\sx}_{M,W}(m_0) \dots \extend^{\sx}_{M,W}(m_{N-1}))) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -1910,7 +1911,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\SHARED \\ \wedge & \X{ea} + M \cdot N / 8 \leq n \\ \wedge & \bytes_{\iM}(m_k) = b^\ast[k \cdot M/8 \slice M/8] \\ - \wedge & c = \lanes^{-1}_{\X{i}W\K{x}N}(\extend^{\sx}_{M,W}(m_0) \dots \extend^{\sx}_{M,W}(m_{N-1}))) \\[1ex] + \wedge & c = \lanes^{-1}_{\K{i}W\K{x}N}(\extend^{\sx}_{M,W}(m_0) \dots \extend^{\sx}_{M,W}(m_{N-1}))) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -1980,7 +1981,7 @@ Memory Instructions 13. Let :math:`L` be the integer :math:`128 / N`. -14. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\iN\K{x}L}(n^L)`. +14. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\IN\K{x}L}(n^L)`. 15. Push the value :math:`\V128.\CONST~c` to the stack. @@ -1995,7 +1996,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\UNSHARED \\ \wedge & \X{ea} + N/8 \leq |\X{mem}.\MIDATA| \\ \wedge & \bytes_{\iN}(n) = \X{mem}.\MIDATA[\X{ea} \slice N/8] \\ - \wedge & c = \lanes^{-1}_{\iN\K{x}L}(n^L)) \\[1ex] + \wedge & c = \lanes^{-1}_{\IN\K{x}L}(n^L)) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -2015,7 +2016,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\SHARED \\ \wedge & \X{ea} + N/8 \leq n \\ \wedge & \bytes_{\iN}(n) = b^\ast \\ - \wedge & c = \lanes^{-1}_{\iN\K{x}L}(n^L)) \\[1ex] + \wedge & c = \lanes^{-1}_{\IN\K{x}L}(n^L)) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -2193,9 +2194,9 @@ Memory Instructions 15. Let :math:`L` be :math:`128 / N`. -16. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(v)`. +16. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\IN\K{x}L}(v)`. -17. Let :math:`c` be the result of computing :math:`\lanes^{-1}_{\K{i}N\K{x}L}(j^\ast \with [x] = r)`. +17. Let :math:`c` be the result of computing :math:`\lanes_{\IN\K{x}L}(j^\ast \with [x] = r)`. 18. Push the value :math:`\V128.\CONST~c` to the stack. @@ -2210,7 +2211,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\UNSHARED \\ \wedge & \X{ea} + N/8 \leq |\X{mem}.\MIDATA| \\ \wedge & \bytes_{\iN}(n) = \X{mem}.\MIDATA[\X{ea} \slice N/8] \\ - \wedge & c = \lanes^{-1}_{\K{i}N\K{x}L}(\lanes_{\K{i}N\K{x}L}(v) \with [x] = r)) \\[1ex] + \wedge & c = \lanes^{-1}_{\IN\K{x}L}(\lanes_{\IN\K{x}L}(v) \with [x] = r)) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -2230,7 +2231,7 @@ Memory Instructions (\iff & \X{mem}.\MITYPE = \limits~\SHARED \\ \wedge & \X{ea} + N/8 \leq n \\ \wedge & \bytes_{\iN}(n) = b^\ast \\ - \wedge & c = \lanes^{-1}_{\K{i}N\K{x}L}(\lanes_{\K{i}N\K{x}L}(v) \with [x] = r)) \\[1ex] + \wedge & c = \lanes^{-1}_{\IN\K{x}L}(\lanes_{\IN\K{x}L}(v) \with [x] = r)) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -2402,7 +2403,7 @@ Memory Instructions 12. Let :math:`L` be :math:`128/N`. -13. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\K{i}N\K{x}L}(c)`. +13. Let :math:`j^\ast` be the result of computing :math:`\lanes_{\IN\K{x}L}(c)`. 14. Let :math:`b^\ast` be the result of computing :math:`\bytes_{\iN}(j^\ast[x])`. @@ -2434,7 +2435,7 @@ Memory Instructions \begin{array}[t]{@{}r@{~}l@{}} (\iff & \X{mem}.\MITYPE = \limits~\UNSHARED \\ \wedge & \X{ea} + N/8 \leq |\X{mem}.\MIDATA| \\ - \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice N/8] = \bytes_{\iN}(\lanes_{\K{i}N\K{x}L}(c)[x])) \\[1ex] + \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice N/8] = \bytes_{\iN}(\lanes_{\IN\K{x}L}(c)[x])) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -2453,7 +2454,7 @@ Memory Instructions \begin{array}[t]{@{}r@{~}l@{}} (\iff & \X{mem}.\MITYPE = \limits~\SHARED \\ \wedge & \X{ea} + N/8 \leq n \\ - \wedge & b^\ast = \bytes_{\iN}(\lanes_{\K{i}N\K{x}L}(c)[x])) \\[1ex] + \wedge & b^\ast = \bytes_{\iN}(\lanes_{\IN\K{x}L}(c)[x])) \\[1ex] \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} diff --git a/document/core/exec/numerics.rst b/document/core/exec/numerics.rst index 71dfef6a9..f9eae6b9d 100644 --- a/document/core/exec/numerics.rst +++ b/document/core/exec/numerics.rst @@ -104,18 +104,19 @@ Conventions: -.. index:: bit, integer, floating-point +.. index:: bit, integer, floating-point, numeric vector .. _aux-bits: Representations ~~~~~~~~~~~~~~~ -Numbers have an underlying binary representation as a sequence of bits: +Numbers and numeric vectors have an underlying binary representation as a sequence of bits: .. math:: \begin{array}{lll@{\qquad}l} - \bits_{\K{i}N}(i) &=& \ibits_N(i) \\ - \bits_{\K{f}N}(z) &=& \fbits_N(z) \\ + \bits_{\IN}(i) &=& \ibits_N(i) \\ + \bits_{\FN}(z) &=& \fbits_N(z) \\ + \bits_{\VN}(i) &=& \ibits_N(i) \\ \end{array} Each of these functions is a bijection, hence they are invertible. @@ -161,48 +162,50 @@ Floating-Point where :math:`M = \significand(N)` and :math:`E = \exponent(N)`. -.. index:: byte, little endian, memory -.. _aux-littleendian: -.. _aux-bytes: +.. index:: numeric vector, shape, lane +.. _aux-lanes: +.. _syntax-i128: -Storage +Vectors ....... -When a number is stored into :ref:`memory `, it is converted into a sequence of :ref:`bytes ` in |LittleEndian|_ byte order: +Numeric vectors have the same underlying representation as an |i128|. +They can also be interpreted as a sequence of numeric values packed into a |V128| with a particular |shape|. .. math:: + \begin{array}{l} \begin{array}{lll@{\qquad}l} - \bytes_t(i) &=& \littleendian(\bits_t(i)) \\[1ex] - \littleendian(\epsilon) &=& \epsilon \\ - \littleendian(d^8~{d'}^\ast~) &=& \littleendian({d'}^\ast)~\ibits_8^{-1}(d^8) \\ + \lanes_{t\K{x}N}(c) &=& + c_0~\dots~c_{N-1} \\ + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}l@{~}l@{~}l} + (\where & B &=& |t| / 8 \\ + \wedge & b^{16} &=& \bytes_{\i128}(c) \\ + \wedge & c_i &=& \bytes_{t}^{-1}(b^{16}[i \cdot B \slice B])) + \end{array} \end{array} -Again these functions are invertible bijections. +These functions are bijections, so they are invertible. -.. index:: numeric vectors, shape -.. _aux-lanes: +.. index:: byte, little endian, memory +.. _aux-littleendian: +.. _aux-bytes: -Vectors +Storage ....... -Numeric vectors have the same underlying representation as an |i128|. They can also be interpreted as a sequence of numeric values packed into a |V128| with a particular |shape|. +When a number is stored into :ref:`memory `, it is converted into a sequence of :ref:`bytes ` in |LittleEndian|_ byte order: .. math:: - \begin{array}{l} \begin{array}{lll@{\qquad}l} - \lanes_{t\K{x}N}(c) &=& - c_0~\dots~c_{N-1} \\ - \end{array} - \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\where & B = |t| / 8 \\ - \wedge & b^{16} = \bytes_{\i128}(c) \\ - \wedge & c_i = \bytes_{t}^{-1}(b^{16}[i \cdot B \slice B])) - \end{array} + \bytes_t(i) &=& \littleendian(\bits_t(i)) \\[1ex] + \littleendian(\epsilon) &=& \epsilon \\ + \littleendian(d^8~{d'}^\ast~) &=& \littleendian({d'}^\ast)~\ibits_8^{-1}(d^8) \\ \end{array} -These functions are bijections, so they are invertible. +Again these functions are invertible bijections. .. index:: integer diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index f5f253746..fda1d710d 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -171,7 +171,7 @@ Occasionally, it is convenient to group operators together according to the foll \end{array} -.. index:: ! vector instruction, numeric vectors, number, value, value type, SIMD +.. index:: ! vector instruction, numeric vector, number, value, value type, SIMD pair: abstract syntax; instruction .. _syntax-laneidx: .. _syntax-shape: diff --git a/document/core/syntax/values.rst b/document/core/syntax/values.rst index 1b155df42..72ff7d3a0 100644 --- a/document/core/syntax/values.rst +++ b/document/core/syntax/values.rst @@ -148,7 +148,7 @@ Conventions * The meta variable :math:`z` ranges over floating-point values where clear from context. -.. index:: ! numeric vectors, integer, floating-point, lane, SIMD +.. index:: ! numeric vector, integer, floating-point, lane, SIMD pair: abstract syntax; vector .. _syntax-vecnum: diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst index 0bd32e033..1efc88b03 100644 --- a/document/core/text/conventions.rst +++ b/document/core/text/conventions.rst @@ -49,6 +49,7 @@ In order to distinguish symbols of the textual syntax from symbols of the abstra (This is a shorthand for :math:`T^n` where :math:`n \leq 1`.) * :math:`x{:}T` denotes the same language as the nonterminal :math:`T`, but also binds the variable :math:`x` to the attribute synthesized for :math:`T`. + A pattern may also be used instead of a variable, e.g., :math:`(x,y){:}T`. * Productions are written :math:`\T{sym} ::= T_1 \Rightarrow A_1 ~|~ \dots ~|~ T_n \Rightarrow A_n`, where each :math:`A_i` is the attribute that is synthesized for :math:`\T{sym}` in the given case, usually from attribute variables bound in :math:`T_i`. diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index c34077326..5aab9b32c 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -292,7 +292,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~\expr^n{:}\Tvec(\Telemexpr)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Telemexpr)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Treftype~~\Tvec(\Telemexpr)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} @@ -302,7 +302,7 @@ An :ref:`element segment ` can be given inline with a table definitio \production{module field} & \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)} \\ & \qquad - \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\text{func}~~\Tvec(\Tfuncidx)~\text{)} \\ & \qquad\qquad (\iff \Tid^? \neq \epsilon \wedge \Tid' = \Tid^? \vee \Tid^? = \epsilon \wedge \Tid' \idfresh) \\ \end{array} diff --git a/document/core/util/bikeshed_fixup.py b/document/core/util/bikeshed_fixup.py index 05439207f..568c67b57 100755 --- a/document/core/util/bikeshed_fixup.py +++ b/document/core/util/bikeshed_fixup.py @@ -59,7 +59,7 @@ def Main(): ) data = data.replace( - """IEEE 754-2019""", + """IEEE 754""", "[[!IEEE-754-2019]]" ) diff --git a/document/core/util/macros.def b/document/core/util/macros.def index d529e70d2..e6b809d2c 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -187,13 +187,15 @@ .. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} .. |F64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64}} .. |V128| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{v128}} +.. |IN| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i}N} +.. |FN| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f}N} +.. |VN| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{v}N} .. |I8X16| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i8x16}} .. |I16X8| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i16x8}} .. |I32X4| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32x4}} .. |I64X2| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i64x2}} .. |F32X4| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32x4}} .. |F64X2| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64x2}} -.. |I128| mathdef:: \K{i128} .. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} .. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} @@ -1310,8 +1312,8 @@ .. |ieee| mathdef:: \xref{exec/numerics}{aux-ieee}{\F{float}} .. |nans| mathdef:: \xref{exec/numerics}{aux-nans}{\F{nans}} .. |trunc| mathdef:: \xref{exec/numerics}{aux-trunc}{\F{trunc}} -.. |satu| mathdef:: \xref{exec/numerics}{aux-sat_u}{\F{sat}^{\K{u}}} -.. |sats| mathdef:: \xref{exec/numerics}{aux-sat_s}{\F{sat}^{\K{s}}} +.. |satu| mathdef:: \xref{exec/numerics}{aux-sat_u}{\F{sat\_u}} +.. |sats| mathdef:: \xref{exec/numerics}{aux-sat_s}{\F{sat\_s}} .. |lanes| mathdef:: \xref{exec/numerics}{aux-lanes}{\F{lanes}} diff --git a/interpreter/.gitignore b/interpreter/.gitignore index 0a02ff708..ced4eafb6 100644 --- a/interpreter/.gitignore +++ b/interpreter/.gitignore @@ -1,13 +1,6 @@ -*.cmo -*.cmx -*.native -*.byte -*.opt -*.unopt -*.js -*.zip -*.mlpack _build wasm -wasm.debug - +*.install +*.js +*.zip +opam diff --git a/interpreter/Makefile b/interpreter/Makefile index 3294e2682..d67882b29 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -1,4 +1,4 @@ -# This Makefile uses ocamlbuild but does not rely on ocamlfind or the Opam +# This Makefile uses dune but does not rely on ocamlfind or the Opam # package manager to build. However, Opam package management is available # optionally through the check/install/uninstall targets. # @@ -9,131 +9,45 @@ # Configuration -NAME = wasm -UNOPT = $(NAME).debug -OPT = $(NAME) -LIB = $(NAME) +NAME = wasm +OPT = $(NAME).exe ZIP = $(NAME).zip -JSLIB = wast -WINMAKE = winmake.bat - -DIRS = util syntax binary text valid runtime exec script host main tests -LIBS = -FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3' -OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) -OCB = $(OCBA) $(LIBS:%=-libs %) -JSO = js_of_ocaml -q --opt 3 -JS = # set to JS shell command to run JS tests, empty to skip +JSLIB = wast.js +BUILDDIR = _build/default -# Main targets +JS = # set to JS shell command to run JS tests, empty to skip -.PHONY: default opt unopt libopt libunopt jslib all land zip smallint dunebuild -default: opt -debug: unopt -opt: $(OPT) -unopt: $(UNOPT) -libopt: _build/$(LIB).cmx _build/$(LIB).cmxa -libunopt: _build/$(LIB).cmo _build/$(LIB).cma -jslib: $(JSLIB).js -all: unopt opt libunopt libopt test -land: $(WINMAKE) all -zip: $(ZIP) -smallint: smallint.native -ci: land wast.js dunebuild +# Main targets -dunebuild: - dune build +.PHONY: default opt jslib all zip smallint +default: $(OPT) +jslib: $(JSLIB) +all: $(OPT) test +zip: $(ZIP) +smallint: smallint.exe +ci: all jslib # Building executable +.PHONY: $(NAME).exe +$(NAME).exe: + rm -f $(NAME) + dune build $@ + cp $(BUILDDIR)/$(OPT) $(NAME) -empty = -space = $(empty) $(empty) -comma = , - -.INTERMEDIATE: _tags -_tags: - echo >$@ "true: bin_annot" - echo >>$@ "true: debug" - echo >>$@ "<{$(subst $(space),$(comma),$(DIRS))}/*.cmx>: for-pack($(PACK))" - -$(UNOPT): main.byte - mv $< $@ - -$(OPT): main.native - mv $< $@ - -.PHONY: main.byte main.native -main.byte: _tags - $(OCB) -quiet $@ - -main.native: _tags - $(OCB) -quiet $@ - -.PHONY: smallint.byte smallint.native -smallint.byte: _tags - $(OCB) -quiet $@ -smallint.native: _tags - $(OCB) -quiet $@ - - -# Building library - -FILES = $(shell ls $(DIRS:%=%/*) | grep '[.]ml[^.]*$$') -PACK = $(shell echo `echo $(LIB) | sed 's/^\(.\).*$$/\\1/g' | tr [:lower:] [:upper:]``echo $(LIB) | sed 's/^.\(.*\)$$/\\1/g'`) - -.INTERMEDIATE: $(LIB).mlpack -$(LIB).mlpack: $(DIRS) - ls $(FILES) \ - | sed 's:\(.*/\)\{0,1\}\(.*\)\.[^\.]*:\2:' \ - | grep -v main \ - | sort | uniq \ - >$@ - -.INTERMEDIATE: $(LIB).mllib -$(LIB).mllib: - echo Wasm >$@ - -_build/$(LIB).cmo: $(FILES) $(LIB).mlpack _tags Makefile - $(OCB) -quiet $(LIB).cmo - -_build/$(LIB).cmx: $(FILES) $(LIB).mlpack _tags Makefile - $(OCB) -quiet $(LIB).cmx - -_build/$(LIB).cma: $(FILES) $(LIB).mllib _tags Makefile - $(OCBA) -quiet $(LIB).cma - -_build/$(LIB).cmxa: $(FILES) $(LIB).mllib _tags Makefile - $(OCBA) -quiet $(LIB).cmxa - +.PHONY: smallint.exe +smallint.exe: + dune build $@ # Building JavaScript library -JSLIB_DIR = meta/jslib -JSLIB_FLAGS = -I $(JSLIB_DIR) -use-ocamlfind -pkg js_of_ocaml -pkg js_of_ocaml-ppx - -.INTERMEDIATE: $(JSLIB).byte -$(JSLIB).byte: $(JSLIB_DIR)/$(JSLIB).ml - $(OCBA) $(JSLIB_FLAGS) $@ - -$(JSLIB).js: $(JSLIB).byte - $(JSO) $< - -# Building Windows build file - -$(WINMAKE): clean - echo rem Auto-generated from Makefile! >$@ - echo set NAME=$(NAME) >>$@ - echo if \'%1\' neq \'\' set NAME=%1 >>$@ - $(OCB) main.byte \ - | grep -v ocamldep \ - | grep -v mkdir \ - | sed s:`which ocaml`:ocaml:g \ - | sed s:main/main.d.byte:%NAME%.exe: \ - >>$@ +$(JSLIB): $(BUILDDIR)/$(JSLIB) + cp $< $@ +$(BUILDDIR)/$(JSLIB): + dune build $(JSLIB) # Executing test suite @@ -142,67 +56,60 @@ TESTDIR = ../test/core TESTFILES = $(shell cd $(TESTDIR); ls *.wast; ls [a-z]*/*.wast) TESTS = $(TESTFILES:%.wast=%) -.PHONY: test debugtest partest dune-test +.PHONY: test partest dune-test test: $(OPT) smallint - $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) - ./smallint.native -debugtest: $(UNOPT) smallint - $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) - ./smallint.native + $(TESTDIR)/run.py --wasm `pwd`/$(BUILDDIR)/$(OPT) $(if $(JS),--js '$(JS)',) + dune exec ./smallint.exe test/%: $(OPT) - $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast -debugtest/%: $(UNOPT) - $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast + $(TESTDIR)/run.py --wasm `pwd`/$(BUILDDIR)/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast run/%: $(OPT) ./$(OPT) $(TESTDIR)/$*.wast -debug/%: $(UNOPT) - ./$(UNOPT) $(TESTDIR)/$*.wast -partest: $(TESTS:%=quiettest/%) +partest: $(TESTS:%=quiettest/%) @echo All tests passed. quiettest/%: $(OPT) @ ( \ - $(TESTDIR)/run.py 2>$(@F).out --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast && \ + $(TESTDIR)/run.py 2>$(@F).out --wasm `pwd`/$(BUILDDIR)/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast && \ rm $(@F).out \ ) || \ cat $(@F).out || rm $(@F).out || exit 1 smallinttest: smallint - @./smallint.native + dune exec ./smallint.exe dunetest: dune test +install: + dune build -p $(NAME) @install + dune install + +opam-release/%: + git tag opam-$* + git push --tags + rm -f opam-$*.zip + wget https://github.com/WebAssembly/spec/archive/opam-$*.zip + cp wasm.opam opam + echo "url {" >> opam + echo " src: \"https://github.com/WebAssembly/spec/archive/opam-$*.zip\"" >> opam + echo " checksum: \"md5=`md5 -q opam-$*.zip`\"" >> opam + echo "}" >> opam + rm opam-$*.zip + @echo Created file ./opam, submit to github opam-repository/packages/wasm/wasm.$*/opam # Miscellaneous targets .PHONY: clean -$(ZIP): $(WINMAKE) - git archive --format=zip --prefix=$(NAME)/ -o $@ HEAD +$(ZIP): + git archive --format=zip --prefix=$(NAME)/ -o $@ HEAD clean: - rm -rf _build/jslib $(LIB).mlpack _tags $(JSLIB).js - $(OCB) -clean - - -# Opam support - -.PHONY: check install uninstall - -check: - # Check that we can find all relevant libraries - # when using ocamlfind - ocamlfind query $(LIBS) - -install: _build/$(LIB).cmx _build/$(LIB).cmo - ocamlfind install $(LIB) meta/findlib/META _build/$(LIB).o \ - $(wildcard _build/$(LIB).cm*) \ - $(wildcard $(DIRS:%=%/*.mli)) + dune clean -uninstall: - ocamlfind remove $(LIB) +distclean: clean + rm -f $(NAME) $(JSLIB) diff --git a/interpreter/README.md b/interpreter/README.md index fc2a1827a..1df7ff715 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -17,15 +17,14 @@ The text format defines modules in S-expression syntax. Moreover, it is generali You'll need OCaml 4.12 or higher. Instructions for installing a recent version of OCaml on multiple platforms are available [here](https://ocaml.org/docs/install.html). On most platforms, the recommended way is through [OPAM](https://ocaml.org/docs/install.html#OPAM). +You'll also need to install the dune build system. See the [installation instructions](https://github.com/ocaml/dune#installation-1). + Once you have OCaml, simply do ``` make ``` -You'll get an executable named `./wasm`. This is a byte code executable. If you want a (faster) native code executable, do -``` -make opt -``` +You'll get an executable named `./wasm`. To run the test suite, ``` make test @@ -34,12 +33,6 @@ To do everything: ``` make all ``` -Before committing changes, you should do -``` -make land -``` -That builds `all`, plus updates `winmake.bat`. - #### Building on Windows @@ -49,12 +42,6 @@ The instructions depend on how you [installed OCaml on Windows](https://ocaml.or 2. *Windows Subsystem for Linux* (WSL): You can build the interpreter using `make`, as described above. -3. *From source*: If you just want to build the interpreter and don't care about modifying it, you don't need to install the Cygwin core that comes with the installer. Just install OCaml itself and run -``` -winmake.bat -``` -in a Windows shell, which creates a program named `wasm`. Note that this will be a byte code executable only, i.e., somewhat slower. - In any way, in order to run the test suite you'll need to have Python installed. If you used Option 3, you can invoke the test runner `runtests.py` directly instead of doing it through `make`. diff --git a/interpreter/dune b/interpreter/dune index 48274aad9..c0e9c292f 100644 --- a/interpreter/dune +++ b/interpreter/dune @@ -1,16 +1,16 @@ (include_subdirs unqualified) (library - (name wasm) - ; The 'main' module shall not be part of the library, as it would start the + (public_name wasm) + ; The 'wasm' module shall not be part of the library, as it would start the ; Wasm REPL every time in all the dependencies. ; We exclude the 'wast' module as it is only used for the JS build. ; 'smallint' is a separate test module. - (modules :standard \ main smallint wast)) + (modules :standard \ main wasm smallint wast)) (executable - (name main) - (modules main) + (public_name wasm) + (modules wasm) (libraries wasm) (flags (-open Wasm))) @@ -22,6 +22,23 @@ (flags (-open Wasm))) +(executable + (name wast) + (modules wast) + (modes js) + (libraries js_of_ocaml wasm) + (preprocess (pps js_of_ocaml-ppx))) + +(rule + (targets wasm.ml) + (deps main/main.ml) + (action (copy main/main.ml wasm.ml))) + +(rule + (targets wast.js) + (deps wast.bc.js) + (action (copy wast.bc.js wast.js))) + (subdir text (rule @@ -42,10 +59,10 @@ (rule (alias runtest) (deps - ./main.exe + ./wasm.exe ./smallint.exe (source_tree ../test)) (action (progn - (run ../test/core/run.py --wasm ./main.exe) + (run ../test/core/run.py --wasm ./wasm.exe) (run ./smallint.exe)))) diff --git a/interpreter/dune-project b/interpreter/dune-project index c994249ac..0d15135d3 100644 --- a/interpreter/dune-project +++ b/interpreter/dune-project @@ -1 +1,20 @@ (lang dune 2.9) + +(name wasm) + +(generate_opam_files true) + +(license Apache-2.0) + +(source + (github WebAssembly/spec)) + +(authors "Andreas Rossberg = 4.12)))) diff --git a/interpreter/exec/eval_num.ml b/interpreter/exec/eval_num.ml index f1245a133..40dd1be07 100644 --- a/interpreter/exec/eval_num.ml +++ b/interpreter/exec/eval_num.ml @@ -195,4 +195,3 @@ let eval_binop = op I32Op.binop I64Op.binop F32Op.binop F64Op.binop let eval_testop = op I32Op.testop I64Op.testop F32Op.testop F64Op.testop let eval_relop = op I32Op.relop I64Op.relop F32Op.relop F64Op.relop let eval_cvtop = op I32CvtOp.cvtop I64CvtOp.cvtop F32CvtOp.cvtop F64CvtOp.cvtop - diff --git a/interpreter/exec/v128.ml b/interpreter/exec/v128.ml index 550fd9bfa..873035ad3 100644 --- a/interpreter/exec/v128.ml +++ b/interpreter/exec/v128.ml @@ -477,7 +477,7 @@ let to_hex_string s = let of_strings shape ss = if List.length ss <> num_lanes shape then - raise (Invalid_argument "wrong length"); + invalid_arg "wrong length"; let open Bytes in let b = create bytewidth in (match shape with diff --git a/interpreter/meta/jslib/wast.ml b/interpreter/jslib/wast.ml similarity index 99% rename from interpreter/meta/jslib/wast.ml rename to interpreter/jslib/wast.ml index 9af04f918..0ab4bd8fd 100644 --- a/interpreter/meta/jslib/wast.ml +++ b/interpreter/jslib/wast.ml @@ -1,6 +1,7 @@ (* Implements a wrapper library that allows the use of the reference * interpreter's encode/decode functionality in JavaScript. *) +open Wasm open Js_of_ocaml let _ = diff --git a/interpreter/main/main.ml b/interpreter/main/main.ml index beeb98049..e626a27de 100644 --- a/interpreter/main/main.ml +++ b/interpreter/main/main.ml @@ -1,5 +1,5 @@ let name = "wasm" -let version = "2.0" +let version = "2.0.1" let configure () = Import.register (Utf8.decode "spectest") Spectest.lookup; diff --git a/interpreter/meta/findlib/META b/interpreter/meta/findlib/META deleted file mode 100644 index 2c1d96dd0..000000000 --- a/interpreter/meta/findlib/META +++ /dev/null @@ -1,4 +0,0 @@ -description = "A library for writing/reading/running WebAssembly binaries" -requires = "bigarray,str" -archive(byte) = "wasm.cmo" -archive(native) = "wasm.cmx" diff --git a/interpreter/runtime/data.ml b/interpreter/runtime/data.ml index e73cd2f31..f63a2aaa3 100644 --- a/interpreter/runtime/data.ml +++ b/interpreter/runtime/data.ml @@ -1,7 +1,15 @@ type data = string ref type t = data +exception Bounds + let alloc bs = ref bs + let size seg = I64.of_int_u (String.length !seg) -let load seg i = (!seg).[Int64.to_int i] + +let load seg i = + let i' = Int64.to_int i in + if i' < 0 || i' >= String.length !seg then raise Bounds; + !seg.[i'] + let drop seg = seg := "" diff --git a/interpreter/runtime/elem.ml b/interpreter/runtime/elem.ml index fe8997482..366ec6df0 100644 --- a/interpreter/runtime/elem.ml +++ b/interpreter/runtime/elem.ml @@ -1,7 +1,13 @@ type elem = Values.ref_ list ref type t = elem +exception Bounds + let alloc rs = ref rs let size seg = Lib.List32.length !seg -let load seg i = Lib.List32.nth !seg i + +let load seg i = + if i < 0l || i >= Lib.List32.length !seg then raise Bounds; + Lib.List32.nth !seg i + let drop seg = seg := [] diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index e2c1fbf70..682626d7a 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -62,10 +62,12 @@ let grow mem delta = mem.content <- after let load_byte mem a = - try Array1_64.get mem.content a with Invalid_argument _ -> raise Bounds + if a < 0L || a >= Array1_64.dim mem.content then raise Bounds; + Array1_64.get mem.content a let store_byte mem a b = - try Array1_64.set mem.content a b with Invalid_argument _ -> raise Bounds + if a < 0L || a >= Array1_64.dim mem.content then raise Bounds; + Array1_64.set mem.content a b let load_bytes mem a n = let buf = Buffer.create n in diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index bb10cab8b..e7fc317e8 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -47,14 +47,17 @@ let grow tab delta r = tab.content <- after let load tab i = - try Lib.Array32.get tab.content i with Invalid_argument _ -> raise Bounds + if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; + Lib.Array32.get tab.content i let store tab i r = let TableType (lim, t) = tab.ty in if type_of_ref r <> t then raise Type; - try Lib.Array32.set tab.content i r with Invalid_argument _ -> raise Bounds + if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; + Lib.Array32.set tab.content i r let blit tab offset rs = let data = Array.of_list rs in - try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data) - with Invalid_argument _ -> raise Bounds + let len = Lib.Array32.length data in + if offset < 0l || offset > Int32.sub (Lib.Array32.length tab.content) len then raise Bounds; + Lib.Array32.blit data 0l tab.content offset len diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 9d1979f23..682dee052 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -742,11 +742,11 @@ elem_expr_list : elem_var_list : | var_list { let f = function {at; _} as x -> [ref_func x @@ at] @@ at in - fun c lookup -> List.map f ($1 c lookup) } + fun c -> List.map f ($1 c func) } elem_list : | elem_kind elem_var_list - { ($1, fun c -> $2 c func) } + { ($1, fun c -> $2 c) } | ref_type elem_expr_list { ($1, fun c -> $2 c) } @@ -778,7 +778,7 @@ elem : { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - { etype = FuncRefType; einit = $5 c func; + { etype = FuncRefType; einit = $5 c; emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : @@ -798,19 +798,19 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = $4 c func in + let einit = $4 c :: $5 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [{etype = FuncRefType; einit; emode} @@ at], + [{etype = $1; einit; emode} @@ at], [], [] } - | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = (fun c -> $4 c :: $5 c) c in + let einit = $4 c in let size = Lib.List32.length einit in let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index 76757eb72..90c4e4fe0 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -156,7 +156,7 @@ module Array32 = struct let make n x = if n < 0l || Int64.of_int32 n > Int64.of_int max_int then - raise (Invalid_argument "Array32.make"); + invalid_arg "Array32.make"; Array.make (Int32.to_int n) x let length a = Int32.of_int (Array.length a) @@ -179,7 +179,7 @@ struct struct let create kind layout n = if n < 0L || n > Int64.of_int max_int then - raise (Invalid_argument "Bigarray.Array1_64.create"); + invalid_arg "Bigarray.Array1_64.create"; Array1.create kind layout (Int64.to_int n) let dim a = Int64.of_int (Array1.dim a) @@ -204,7 +204,7 @@ struct let force o = match o with | Some y -> y - | None -> raise (Invalid_argument "Option.force") + | None -> invalid_arg "Option.force" let map f = function | Some x -> Some (f x) diff --git a/interpreter/wasm.opam b/interpreter/wasm.opam new file mode 100644 index 000000000..5d5984106 --- /dev/null +++ b/interpreter/wasm.opam @@ -0,0 +1,32 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: + "Library to read and write WebAssembly (Wasm) files and manipulate their AST" +maintainer: ["Andreas Rossberg = "2.9"} + "ocaml" {>= "4.12"} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "--promote-install-files=false" + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["dune" "install" "-p" name "--create-install-files" name] +] +dev-repo: "git+https://github.com/WebAssembly/spec.git" diff --git a/interpreter/winmake.bat b/interpreter/winmake.bat deleted file mode 100644 index 6ff7e8caa..000000000 --- a/interpreter/winmake.bat +++ /dev/null @@ -1,75 +0,0 @@ -rem Auto-generated from Makefile! -set NAME=wasm -if '%1' neq '' set NAME=%1 -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/numeric_error.cmo exec/numeric_error.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/int.cmo exec/int.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/lib.cmi util/lib.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32.cmo exec/i32.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/float.cmo exec/float.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/types.cmo syntax/types.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32.cmo exec/f32.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64.cmo exec/f64.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64.cmo exec/i64.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/values.cmo syntax/values.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/memory.cmi runtime/memory.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/source.cmi util/source.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/ast.cmo syntax/ast.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/func.cmi runtime/func.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/global.cmi runtime/global.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/table.cmi runtime/table.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/instance.cmo runtime/instance.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval.cmi exec/eval.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/utf8.cmi binary/utf8.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I host -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I valid -o host/env.cmo host/env.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o main/flags.cmo main/flags.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/import.cmi script/import.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/run.cmi script/run.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I host -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I valid -o host/spectest.cmo host/spectest.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o main/main.cmo main/main.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/error.cmi util/error.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/script.cmo script/script.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/decode.cmi binary/decode.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/encode.cmi binary/encode.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/js.cmi script/js.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parse.cmi text/parse.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/print.cmi text/print.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I valid -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -o valid/valid.cmi valid/valid.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/import.cmo script/import.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/run.cmo script/run.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/utf8.cmo binary/utf8.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval_numeric.cmi exec/eval_numeric.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64_convert.cmi exec/i64_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval.cmo exec/eval.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/func.cmo runtime/func.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/source.cmo util/source.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32_convert.cmi exec/f32_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64_convert.cmi exec/f64_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32_convert.cmi exec/i32_convert.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/error.cmo util/error.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/eval_numeric.cmo exec/eval_numeric.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/global.cmo runtime/global.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i64_convert.cmo exec/i64_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/lib.cmo util/lib.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/memory.cmo runtime/memory.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I runtime -I main -I syntax -I text -I binary -I exec -I script -I util -I host -I valid -o runtime/table.cmo runtime/table.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f32_convert.cmo exec/f32_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/f64_convert.cmo exec/f64_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I exec -I main -I syntax -I text -I binary -I script -I runtime -I util -I host -I valid -o exec/i32_convert.cmo exec/i32_convert.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I syntax -I main -I text -I binary -I exec -I script -I runtime -I util -I host -I valid -o syntax/operators.cmo syntax/operators.ml -ocamlyacc text/parser.mly -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parser.cmi text/parser.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/lexer.cmi text/lexer.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/sexpr.cmi util/sexpr.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/arrange.cmi text/arrange.mli -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/decode.cmo binary/decode.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I binary -I main -I syntax -I text -I exec -I script -I runtime -I util -I host -I valid -o binary/encode.cmo binary/encode.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I script -I main -I syntax -I text -I binary -I exec -I runtime -I util -I host -I valid -o script/js.cmo script/js.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parse.cmo text/parse.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/print.cmo text/print.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I valid -I main -I syntax -I text -I binary -I exec -I script -I runtime -I util -I host -o valid/valid.cmo valid/valid.ml -ocamllex.opt -q text/lexer.mll -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/lexer.cmo text/lexer.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/parser.cmo text/parser.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I text -I main -I syntax -I binary -I exec -I script -I runtime -I util -I host -I valid -o text/arrange.cmo text/arrange.ml -ocamlc.opt -c -w +a-3-4-27-42-44-45 -warn-error +a -I util -I main -I syntax -I text -I binary -I exec -I script -I runtime -I host -I valid -o util/sexpr.cmo util/sexpr.ml -ocamlc.opt bigarray.cma -I util -I binary -I exec -I syntax -I runtime -I host -I main -I script -I text -I valid util/lib.cmo binary/utf8.cmo exec/float.cmo exec/f32.cmo exec/f64.cmo exec/numeric_error.cmo exec/int.cmo exec/i32.cmo exec/i64.cmo exec/i32_convert.cmo exec/f32_convert.cmo exec/i64_convert.cmo exec/f64_convert.cmo syntax/types.cmo syntax/values.cmo runtime/memory.cmo util/source.cmo syntax/ast.cmo exec/eval_numeric.cmo runtime/func.cmo runtime/global.cmo runtime/table.cmo runtime/instance.cmo util/error.cmo exec/eval.cmo host/env.cmo host/spectest.cmo main/flags.cmo script/import.cmo binary/encode.cmo syntax/operators.cmo binary/decode.cmo script/script.cmo text/parser.cmo text/lexer.cmo text/parse.cmo script/js.cmo util/sexpr.cmo text/arrange.cmo text/print.cmo valid/valid.cmo script/run.cmo main/main.cmo -o main/main.byte diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 1b642261a..335496f08 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -404,19 +404,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\1a" ;; drop + "\0b" ;; end ) "integer representation too long" ) @@ -461,19 +461,19 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\12\01" ;; Code section ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end + "\10\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\80\00" ;; offset 2 with one byte too many + "\0b" ;; end ) "integer representation too long" ) @@ -730,40 +730,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\1a" ;; drop + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\10\01" ;; Code section ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end + "\0e\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\28" ;; i32.load + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\1a" ;; drop + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary @@ -843,41 +845,42 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\10" ;; offset 2 with unused bits set + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\01" ;; Memory section + "\0a\11\01" ;; Code section ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end + "\0f\01\01" ;; local type count + "\7f" ;; i32 + "\41\00" ;; i32.const 0 + "\41\03" ;; i32.const 3 + "\36" ;; i32.store + "\02" ;; alignment 2 + "\82\80\80\80\80\80\80\80\80\40" ;; offset 2 with some unused bits set + "\0b" ;; end ) - "integer too large" + ;; TODO: This changes to "integer too large" with memory64. + "integer representation too long" ) ;; Signed LEB128s sign-extend @@ -963,7 +966,6 @@ "integer too large" ) - (module binary "\00asm" "\01\00\00\00" "\01\04\01" ;; type section @@ -1000,3 +1002,81 @@ ) "integer representation too long" ) + +;; Data segment tags and memory index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\07\01" ;; Data section with 1 entry + "\80\00" ;; Active segment, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\08\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit memory index + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\09\01" ;; Data section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit memory index, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) + +;; Element segment tags and table index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\07\01" ;; Element section with 1 entry + "\80\00" ;; Active segment + "\41\00\0b\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Active segment + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\00" ;; explicit table index + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\0a\01" ;; Element section with 1 entry + "\82\00" ;; Active segment, encoded with 2 bytes + "\80\00" ;; explicit table index, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) + +;; Type section with signed LEB128 encoded type +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01" ;; Type section id + "\05" ;; Type section length + "\01" ;; Types vector length + "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding + "\00\00" + ) + "integer representation too long" +) diff --git a/test/core/binary.wast b/test/core/binary.wast index 526e0a20e..c777bebb0 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -51,368 +51,6 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\01\00\01\01\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\01\00\01\01\00") "malformed section id") -;; Unsigned LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\04\01" ;; Memory section with 1 entry - "\00\82\00" ;; no max, minimum 2 -) -(module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\00" ;; no max, minimum 2 -) - -;; Signed LEB128 can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\7f" ;; i32.const -1 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\00" ;; i32.const 0 - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\7f" ;; i32.const -1 - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\07\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with unused bits set - "\0b" ;; end -) -(module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with unused bits unset - "\0b" ;; end -) - -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\06\01" ;; Data section with 1 entry - "\00" ;; Memory index 0 - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\06\01" ;; Element section with 1 entry - "\00" ;; Table index 0 - "\41\00\0b\00" ;; (i32.const 0) with no elements -) - -;; Data segment tags and memory index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\07\01" ;; Data section with 1 entry - "\80\00" ;; Active segment, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\08\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit memory index - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) -(module binary - "\00asm" "\01\00\00\00" - "\05\03\01" ;; Memory section with 1 entry - "\00\00" ;; no max, minimum 0 - "\0b\09\01" ;; Data section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit memory index, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with contents "" -) - -;; Element segment tags and table index can have non-minimal length -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry - "\80\00" ;; Active segment - "\41\00\0b\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\02" ;; Active segment - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\09\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\00" ;; explicit table index - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) -(module binary - "\00asm" "\01\00\00\00" - "\04\04\01" ;; Table section with 1 entry - "\70\00\00" ;; no max, minimum 0, funcref - "\09\0a\01" ;; Element section with 1 entry - "\82\00" ;; Active segment, encoded with 2 bytes - "\80\00" ;; explicit table index, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements -) - -;; Type section with signed LEB128 encoded type -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01" ;; Type section id - "\05" ;; Type section length - "\01" ;; Types vector length - "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding - "\00\00" - ) - "integer representation too long" -) - -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - ;; Function with missing end marker (between two functions) (assert_malformed (module binary @@ -470,386 +108,17 @@ "section size mismatch" ) -;; Unsigned LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\08\01" ;; Memory section with 1 entry - "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) +;; Init expression with missing end marker (assert_malformed (module binary "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\80\00" ;; alignment 2 with one byte too many - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\12\01" ;; Code section - ;; function 0 - "\10\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\80\00" ;; offset 2 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Signed LEB128 must not be overlong -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0b\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\10\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many - "\0b" ;; end - ) - "integer representation too long" -) - -;; Unsigned LEB128s zero-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\05\07\01" ;; Memory section with 1 entry - "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\10\01" ;; Code section - ;; function 0 - "\0e\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\28" ;; i32.load - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\00" ;; offset 0 - "\1a" ;; drop - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\10" ;; alignment 2 with unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\82\80\80\80\40" ;; alignment 2 with some unused bits set - "\03" ;; offset 3 - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\10" ;; offset 2 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\05\03\01\00\01" ;; Memory section - "\0a\11\01" ;; Code section - - ;; function 0 - "\0f\01\01" ;; local type count - "\7f" ;; i32 - "\41\00" ;; i32.const 0 - "\41\03" ;; i32.const 3 - "\36" ;; i32.store - "\02" ;; alignment 2 - "\82\80\80\80\40" ;; offset 2 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) - -;; Signed LEB128s sign-extend -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0a\01" ;; Global section with 1 entry - "\7f\00" ;; i32, immutable - "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset - "\0b" ;; end - ) - "integer too large" -) - -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set - "\0b" ;; end - ) - "integer too large" -) -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\06\0f\01" ;; Global section with 1 entry - "\7e\00" ;; i64, immutable - "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset - "\0b" ;; end + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\06\05\01\7f\00\41\00" ;; Global section: 1 entry with missing end marker + ;; Missing end marker here + "\0a\04\01\02\00\0b" ;; Code section: 1 function ) - "integer too large" + "illegal opcode" ) ;; memory.grow reserved byte equal to zero. diff --git a/test/core/float_literals.wast b/test/core/float_literals.wast index fefb91fbb..3b3ed76bb 100644 --- a/test/core/float_literals.wast +++ b/test/core/float_literals.wast @@ -352,6 +352,10 @@ (module quote "(global f32 (f32.const 0x1.0p_+1))") "unknown operator" ) +(assert_malformed + (module quote "(global f32 (f32.const nan:0x80_0000))") + "constant out of range" +) (assert_malformed (module quote "(global f64 (f64.const _100))") @@ -505,3 +509,7 @@ (module quote "(global f64 (f64.const 0x1.0p_+1))") "unknown operator" ) +(assert_malformed + (module quote "(global f64 (f64.const nan:0x10_0000_0000_0000))") + "constant out of range" +) diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 7e690cad9..d913c6c7a 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -244,3 +244,62 @@ test(() => { () => memory.grow(kJSEmbeddingMaxTableSize)); }, `Grow WebAssembly.Table object beyond the embedder-defined limit`); +function testModuleSizeLimit(size, expectPass) { + // We do not use `testLimit` here to avoid OOMs due to having multiple big + // modules alive at the same time. + + // Define a WebAssembly module that consists of a single custom section which + // has an empty name. The module size will be `size`. + let buffer; + try { + buffer = new Uint8Array(size); + } catch (e) { + if (e instanceof RangeError) { + // Allocation of a big TypedArray may fail. + return; + } + throw e; + } + const header = [ + kWasmH0, kWasmH1, kWasmH2, kWasmH3, // magic word + kWasmV0, kWasmV1, kWasmV2, kWasmV3, // version + 0 // custom section + ]; + // We calculate the section length so that the total module size is `size`. + // For that we have to calculate the length of the leb encoding of the section + // length. + const sectionLength = size - header.length - + wasmSignedLeb(size).length; + const lengthBytes = wasmSignedLeb(sectionLength); + buffer.set(header); + buffer.set(lengthBytes, header.length); + + if (expectPass) { + test(() => { + assert_true(WebAssembly.validate(buffer)); + }, `Validate module size limit`); + test(() => { + new WebAssembly.Module(buffer); + }, `Compile module size limit`); + promise_test(t => { + return WebAssembly.compile(buffer); + }, `Async compile module size limit`); + } else { + test(() => { + assert_false(WebAssembly.validate(buffer)); + }, `Validate module size over limit`); + test(() => { + assert_throws( + new WebAssembly.CompileError(), + () => new WebAssembly.Module(buffer)); + }, `Compile module size over limit`); + promise_test(t => { + return promise_rejects( + t, new WebAssembly.CompileError(), + WebAssembly.compile(buffer)); + }, `Async compile module size over limit`); + } +} + +testModuleSizeLimit(kJSEmbeddingMaxModuleSize, true); +testModuleSizeLimit(kJSEmbeddingMaxModuleSize + 1, false);