diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 5ce9d1c91..d478ddb33 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -967,7 +967,7 @@ Memory Instructions a. Let :math:`n` be the integer for which :math:`\bytes_{\iN}(n) = b^\ast`. - b. Let :math:`c` be the result of computing :math:`\extend\F{\_}\sx_{N,|t|}(n)`. + b. Let :math:`c` be the result of computing :math:`\extend^{\sx}_{N,|t|}(n)`. 13. Else: @@ -990,7 +990,7 @@ Memory Instructions \\[1ex] \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~(t.\LOAD{N}\K{\_}\sx~\memarg) &\stepto& - S; F; (t.\CONST~\extend\F{\_}\sx_{N,|t|}(n)) + S; F; (t.\CONST~\extend^{\sx}_{N,|t|}(n)) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 0fcade6cc..c3f910bcf 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -796,6 +796,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. + 1. If |result| is ε, return null. 1. Let |function| be the result of creating [=a new Exported Function=] from |result|. 1. Return |function|. @@ -803,7 +804,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. If |value| is null, let |funcaddr| be an empty [=function element=]. + 1. If |value| is null, let |funcaddr| be ε. 1. Otherwise, 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. 1. Let |funcaddr| be |value|.\[[FunctionAddress]]. diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 564dd6ee0..3cc610820 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -253,17 +253,27 @@ application/wasm
Encoding Considerations:
binary
Security Considerations:
-
See see WebAssembly Core Security Considerations
- https://www.w3.org/TR/wasm-core/#security-considerations%E2%91%A0
+
+

WebAssembly is a standard, a safe, portable, low-level code format. The + security considerations associated with executing WebAssembly code are + described in https://www.w3.org/TR/wasm-core/#security-considerations.

+

The WebAssembly format includes no integrity or privacy protection. If + such protection is needed it must be provided externally, e.g., through + the use of HTTPS.

+
Interoperability Considerations:
-
See see WebAssembly Core Conformance
+
See WebAssembly Core Conformance
https://www.w3.org/TR/wasm-core/#conformance
Published specification:
- https://www.w3.org/TR/wasm-core-1/ +
https://www.w3.org/TR/wasm-core-1/ https://www.w3.org/TR/wasm-js-api-1/ - https://www.w3.org/TR/wasm-web-api-1/ + https://www.w3.org/TR/wasm-web-api-1/
Application Usage:
-
The application/wasm media type is already in use as the type used to describe WebAssembly files when sent over HTTP to be executed by browsers, which is a common scenario. Additionally, several WebAssembly runtimes that take advantage of the safety and portability while targeting efficient execution and compact representation.
+
The application/wasm media type is intended for use as the type used to + describe WebAssembly files when sent over HTTP to be executed by browsers, + which is a common scenario. Additionally, the type is used by several + WebAssembly runtimes that take advantage of the safety and portability + while targeting efficient execution and compact representation.
Fragment Identifier Considerations:
None
Restrictions on usage:
diff --git a/interpreter/README.md b/interpreter/README.md index 5f3914e6f..7443504da 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -363,6 +363,36 @@ The `input` and `output` meta commands determine the requested file format from The interpreter supports a "dry" mode (flag `-d`), in which modules are only validated. In this mode, all actions and assertions are ignored. It also supports an "unchecked" mode (flag `-u`), in which module definitions are not validated before use. + +### Spectest host module + +When running scripts, the interpreter predefines a simple host module named `"spectest"` that has the following module type: +``` +(module + (global (export "global_i32") i32) + (global (export "global_i64") i64) + (global (export "global_f32") f32) + (global (export "global_f64") f64) + + (table (export "table") 10 20 funcref) + + (memory (export "memory") 1 2) + + (func (export "print")) + (func (export "print_i32") (param i32)) + (func (export "print_i64") (param i64)) + (func (export "print_f32") (param f32)) + (func (export "print_f64") (param f64)) + (func (export "print_i32_f32") (param i32 f32)) + (func (export "print_f64_f64") (param f64 f64)) +) +``` +The `print` functions are assumes to print their respective argument values to stdout (followed by a newline) and can be used to produce observable output. + +Note: This module predates the `register` command and should no longer be needed for new tests. +We might remove it in the future, so consider it deprecated. + + ### Binary Scripts The grammar of binary scripts is a subset of the grammar for general scripts: diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index a30d85b22..284b970a8 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -35,13 +35,15 @@ let lookup name t = match Utf8.encode name, t with | "print", _ -> ExternFunc (func print (FuncType ([], []))) | "print_i32", _ -> ExternFunc (func print (FuncType ([I32Type], []))) + | "print_i64", _ -> ExternFunc (func print (FuncType ([I64Type], []))) + | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) + | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) | "print_i32_f32", _ -> ExternFunc (func print (FuncType ([I32Type; F32Type], []))) | "print_f64_f64", _ -> ExternFunc (func print (FuncType ([F64Type; F64Type], []))) - | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) - | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) | "global_i32", _ -> ExternGlobal (global (GlobalType (I32Type, Immutable))) + | "global_i64", _ -> ExternGlobal (global (GlobalType (I64Type, Immutable))) | "global_f32", _ -> ExternGlobal (global (GlobalType (F32Type, Immutable))) | "global_f64", _ -> ExternGlobal (global (GlobalType (F64Type, Immutable))) | "table", _ -> ExternTable table diff --git a/test/core/binary.wast b/test/core/binary.wast index fd188d760..8f2e2ba80 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -350,7 +350,24 @@ "zero flag expected" ) -;; No more than 2^32 locals. +;; Local number is unsigned 32 bit +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\0a\0c\01" ;; Code section + + ;; function 0 + "\0a\02" + "\80\80\80\80\10\7f" ;; 0x100000000 i32 + "\02\7e" ;; 0x00000002 i64 + "\0b" ;; end + ) + "integer too large" +) + +;; No more than 2^32-1 locals. (assert_malformed (module binary "\00asm" "\01\00\00\00" @@ -367,6 +384,24 @@ "too many locals" ) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\06\01\60\02\7f\7f\00" ;; Type section: (param i32 i32) + "\03\02\01\00" ;; Function section + "\0a\1c\01" ;; Code section + + ;; function 0 + "\1a\04" + "\80\80\80\80\04\7f" ;; 0x40000000 i32 + "\80\80\80\80\04\7e" ;; 0x40000000 i64 + "\80\80\80\80\04\7d" ;; 0x40000000 f32 + "\80\80\80\80\04\7c" ;; 0x40000000 f64 + "\0b" ;; end + ) + "too many locals" +) + ;; Local count can be 0. (module binary "\00asm" "\01\00\00\00" diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 58abe38a4..d03068744 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1464,6 +1464,16 @@ )) "type mismatch" ) +(assert_invalid + (module (func + (block (result i32) + (block (result i64) + (br_table 0 1 (i32.const 0) (i32.const 0)) + ) + ) + )) + "type mismatch" +) (assert_invalid (module (func $type-index-void-vs-i32 @@ -1552,6 +1562,31 @@ "type mismatch" ) +(assert_invalid + (module + (func (param i32) (result i32) + (loop (result i32) + (block (result i32) + (br_table 0 1 (i32.const 1) (local.get 0)) + ) + ) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (func (param i32) (result i32) + (block (result i32) + (loop (result i32) + (br_table 0 1 (i32.const 1) (local.get 0)) + ) + ) + ) + ) + "type mismatch" +) + (assert_invalid (module (func $unbound-label diff --git a/test/core/data.wast b/test/core/data.wast index d65abf36f..e840a9467 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -359,6 +359,40 @@ "type mismatch" ) +(assert_invalid + (module + (memory 1) + (data (offset (;empty instruction sequence;))) + ) + "type mismatch" +) + +(assert_invalid + (module + (memory 1) + (data (offset (i32.const 0) (i32.const 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (offset (global.get 0) (global.get 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (offset (global.get 0) (i32.const 0))) + ) + "type mismatch" +) + (assert_invalid (module (memory 1) @@ -396,3 +430,29 @@ ;; (module (memory 1) (data (global.get $g)) (global $g (mut i32) (i32.const 0))) ;; "constant expression required" ;; ) + +(assert_invalid + (module + (memory 1) + (data (global.get 0)) + ) + "unknown global 0" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (global.get 1)) + ) + "unknown global 1" +) + +(assert_invalid + (module + (global (import "test" "global-mut-i32") (mut i32)) + (memory 1) + (data (global.get 0)) + ) + "constant expression required" +) \ No newline at end of file diff --git a/test/core/elem.wast b/test/core/elem.wast index 1ea2b0618..ce8ec1f60 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -262,6 +262,41 @@ "type mismatch" ) +(assert_invalid + (module + (table 1 funcref) + (elem (offset (;empty instruction sequence;))) + ) + "type mismatch" +) + +(assert_invalid + (module + (table 1 funcref) + (elem (offset (i32.const 0) (i32.const 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (offset (global.get 0) (global.get 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (offset (global.get 0) (i32.const 0))) + ) + "type mismatch" +) + + (assert_invalid (module (table 1 funcref) @@ -300,6 +335,32 @@ ;; "constant expression required" ;; ) +(assert_invalid + (module + (table 1 funcref) + (elem (global.get 0)) + ) + "unknown global 0" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (global.get 1)) + ) + "unknown global 1" +) + +(assert_invalid + (module + (global (import "test" "global-mut-i32") (mut i32)) + (table 1 funcref) + (elem (global.get 0)) + ) + "constant expression required" +) + ;; Two elements target the same slot (module diff --git a/test/core/exports.wast b/test/core/exports.wast index ef1c4c17e..0c44694db 100644 --- a/test/core/exports.wast +++ b/test/core/exports.wast @@ -25,10 +25,18 @@ (module $Other1) (assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43)) +(assert_invalid + (module (export "a" (func 0))) + "unknown function" +) (assert_invalid (module (func) (export "a" (func 1))) "unknown function" ) +(assert_invalid + (module (import "spectest" "print_i32" (func (param i32))) (export "a" (func 1))) + "unknown function" +) (assert_invalid (module (func) (export "a" (func 0)) (export "a" (func 0))) "duplicate export name" @@ -74,10 +82,18 @@ (module $Other2) (assert_return (get $Global "e") (i32.const 42)) +(assert_invalid + (module (export "a" (global 0))) + "unknown global" +) (assert_invalid (module (global i32 (i32.const 0)) (export "a" (global 1))) "unknown global" ) +(assert_invalid + (module (import "spectest" "global_i32" (global i32)) (export "a" (global 1))) + "unknown global" +) (assert_invalid (module (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 0))) "duplicate export name" @@ -122,10 +138,18 @@ (; TODO: access table ;) +(assert_invalid + (module (export "a" (table 0))) + "unknown table" +) (assert_invalid (module (table 0 funcref) (export "a" (table 1))) "unknown table" ) +(assert_invalid + (module (import "spectest" "table" (table 10 20 funcref)) (export "a" (table 1))) + "unknown table" +) (assert_invalid (module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0))) "duplicate export name" @@ -171,10 +195,18 @@ (; TODO: access memory ;) +(assert_invalid + (module (export "a" (memory 0))) + "unknown memory" +) (assert_invalid (module (memory 0) (export "a" (memory 1))) "unknown memory" ) +(assert_invalid + (module (import "spectest" "memory" (memory 1 2)) (export "a" (memory 1))) + "unknown memory" +) (assert_invalid (module (memory 0) (export "a" (memory 0)) (export "a" (memory 0))) "duplicate export name" diff --git a/test/core/global.wast b/test/core/global.wast index ef1fccbbd..55d7447b1 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -244,6 +244,11 @@ "global is immutable" ) +(assert_invalid + (module (import "spectest" "global_i32" (global i32)) (func (global.set 0 (i32.const 1)))) + "global is immutable" +) + ;; mutable globals can be exported (module (global (mut f32) (f32.const 0)) (export "a" (global 0))) (module (global (export "a") (mut f32) (f32.const 0))) @@ -268,6 +273,11 @@ "constant expression required" ) +(assert_invalid + (module (global i32 (i32.ctz (i32.const 0)))) + "constant expression required" +) + (assert_invalid (module (global i32 (nop))) "constant expression required" @@ -288,6 +298,16 @@ "type mismatch" ) +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0))) + "type mismatch" +) + +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (i32.const 0) (global.get 0))) + "type mismatch" +) + (assert_invalid (module (global i32 (global.get 0))) "unknown global" @@ -298,6 +318,16 @@ "unknown global" ) +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (global.get 2))) + "unknown global" +) + +(assert_invalid + (module (global (import "test" "global-mut-i32") (mut i32)) (global i32 (global.get 0))) + "constant expression required" +) + (module (import "spectest" "global_i32" (global i32)) ) @@ -356,6 +386,68 @@ "malformed mutability" ) +;; global.get with invalid index +(assert_invalid + (module (func (result i32) (global.get 0))) + "unknown global" +) + +(assert_invalid + (module + (global i32 (i32.const 0)) + (func (result i32) (global.get 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (func (result i32) (global.get 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (global i32 (i32.const 0)) + (func (result i32) (global.get 2)) + ) + "unknown global" +) + +;; global.set with invalid index +(assert_invalid + (module (func (i32.const 0) (global.set 0))) + "unknown global" +) + +(assert_invalid + (module + (global i32 (i32.const 0)) + (func (i32.const 0) (global.set 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (func (i32.const 0) (global.set 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (global i32 (i32.const 0)) + (func (i32.const 0) (global.set 2)) + ) + "unknown global" +) + (assert_invalid (module diff --git a/test/core/imports.wast b/test/core/imports.wast index 2f0200dc3..187e0afb9 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -10,6 +10,7 @@ (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) (global (export "global-i32") i32 (i32.const 55)) (global (export "global-f32") f32 (f32.const 44)) + (global (export "global-mut-i64") (mut i64) (i64.const 66)) (table (export "table-10-inf") 10 funcref) ;; (table (export "table-10-20") 10 20 funcref) (memory (export "memory-2-inf") 2) @@ -230,6 +231,7 @@ (module (import "test" "global-i32" (global i32))) (module (import "test" "global-f32" (global f32))) +(module (import "test" "global-mut-i64" (global (mut i64)))) (assert_unlinkable (module (import "test" "unknown" (global i32))) @@ -240,6 +242,55 @@ "unknown import" ) +(assert_unlinkable + (module (import "test" "global-i32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f64)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global i64))) + "incompatible import type" +) + (assert_unlinkable (module (import "test" "func" (global i32))) "incompatible import type" diff --git a/test/core/local_get.wast b/test/core/local_get.wast index ab564cbed..6acab3988 100644 --- a/test/core/local_get.wast +++ b/test/core/local_get.wast @@ -198,29 +198,29 @@ ;; Invalid local index (assert_invalid - (module (func $unbound-local (local i32 i64) (local.get 3))) + (module (func $unbound-local (local i32 i64) (local.get 3) drop)) "unknown local" ) (assert_invalid - (module (func $large-local (local i32 i64) (local.get 14324343))) + (module (func $large-local (local i32 i64) (local.get 14324343) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-param (param i32 i64) (local.get 2))) + (module (func $unbound-param (param i32 i64) (local.get 2) drop)) "unknown local" ) (assert_invalid - (module (func $large-param (param i32 i64) (local.get 714324343))) + (module (func $large-param (param i32 i64) (local.get 714324343) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3))) + (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3) drop)) "unknown local" ) (assert_invalid - (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343))) + (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343) drop)) "unknown local" ) diff --git a/test/core/local_tee.wast b/test/core/local_tee.wast index dde7321ec..a158f0c7c 100644 --- a/test/core/local_tee.wast +++ b/test/core/local_tee.wast @@ -595,45 +595,45 @@ "type mismatch" ) - -;; Invalid local index - (assert_invalid - (module (func $unbound-local (local i32 i64) (local.get 3))) - "unknown local" + (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0)))) + "type mismatch" ) (assert_invalid - (module (func $large-local (local i32 i64) (local.get 14324343))) - "unknown local" + (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0)))) + "type mismatch" +) +(assert_invalid + (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0)))) + "type mismatch" ) + +;; Invalid local index + (assert_invalid - (module (func $unbound-param (param i32 i64) (local.get 2))) + (module (func $unbound-local (local i32 i64) (local.tee 3 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $large-param (local i32 i64) (local.get 714324343))) + (module (func $large-local (local i32 i64) (local.tee 14324343 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3))) + (module (func $unbound-param (param i32 i64) (local.tee 2 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343))) + (module (func $large-param (param i32 i64) (local.tee 714324343 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0)))) - "type mismatch" -) -(assert_invalid - (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0)))) - "type mismatch" + (module (func $unbound-mixed (param i32) (local i32 i64) (local.tee 3 (i32.const 0)) drop)) + "unknown local" ) (assert_invalid - (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0)))) - "type mismatch" + (module (func $large-mixed (param i64) (local i32 i64) (local.tee 214324343 (i32.const 0)) drop)) + "unknown local" )