Repository: bytecodealliance/wasm-tools
Pull request #1575 (2024-05-21 19:39:47)

`wasmparser`: Update validator for custom page sizes
The CG voted today to conservatively allow only two page sizes: 1 byte and 64 KiB. This updates `wasmparser`'s validation to match that decision.


Patch:
diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs
index 4d728dc5..b189c419 100644
--- a/crates/wasmparser/src/validator/core.rs
+++ b/crates/wasmparser/src/validator/core.rs
@@ -905,12 +905,14 @@ impl Module {
                     offset,
                 ));
             }
-            if page_size_log2 > 16 {
+            // Currently 2**0 and 2**16 are the only valid page sizes, but this
+            // may be relaxed to allow any power of two in the future.
+            if page_size_log2 != 0 && page_size_log2 != 16 {
                 return Err(BinaryReaderError::new("invalid custom page size", offset));
             }
             let page_size = 1_u64 << page_size_log2;
             debug_assert!(page_size.is_power_of_two());
-            debug_assert!(page_size <= DEFAULT_WASM_PAGE_SIZE);
+            debug_assert!(page_size == DEFAULT_WASM_PAGE_SIZE || page_size == 1);
             (page_size, page_size_log2)
         } else {
             let page_size_log2 = 16;


Test patch:
diff --git a/tests/local/custom-page-sizes/custom-page-sizes-invalid.wast b/tests/local/custom-page-sizes/custom-page-sizes-invalid.wast
index 83f3db74..8436f570 100644
--- a/tests/local/custom-page-sizes/custom-page-sizes-invalid.wast
+++ b/tests/local/custom-page-sizes/custom-page-sizes-invalid.wast
@@ -1,9 +1,72 @@
+;; Page size that is not a power of two.
 (assert_malformed
   (module quote "(memory 0 (pagesize 3))")
   "invalid custom page size"
 )
 
-;; Power of two page size that is larger than 64KiB.
+;; Power-of-two page sizes that are not 1 or 64KiB.
+(assert_invalid
+  (module (memory 0 (pagesize 2)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 4)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 8)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 16)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 32)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 64)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 128)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 256)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 512)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 1024)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 2048)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 4096)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 8192)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 16384)))
+  "invalid custom page size"
+)
+(assert_invalid
+  (module (memory 0 (pagesize 32768)))
+  "invalid custom page size"
+)
+
+;; Power-of-two page size that is larger than 64KiB.
 (assert_invalid
   (module (memory 0 (pagesize 0x20000)))
   "invalid custom page size"
diff --git a/tests/local/custom-page-sizes/custom-page-sizes.wast b/tests/local/custom-page-sizes/custom-page-sizes.wast
index 3132c15b..0e9909ea 100644
--- a/tests/local/custom-page-sizes/custom-page-sizes.wast
+++ b/tests/local/custom-page-sizes/custom-page-sizes.wast
@@ -1,39 +1,9 @@
 ;; Check all the valid custom page sizes.
 (module (memory 1 (pagesize 1)))
-(module (memory 1 (pagesize 2)))
-(module (memory 1 (pagesize 4)))
-(module (memory 1 (pagesize 8)))
-(module (memory 1 (pagesize 16)))
-(module (memory 1 (pagesize 32)))
-(module (memory 1 (pagesize 64)))
-(module (memory 1 (pagesize 128)))
-(module (memory 1 (pagesize 256)))
-(module (memory 1 (pagesize 512)))
-(module (memory 1 (pagesize 1024)))
-(module (memory 1 (pagesize 2048)))
-(module (memory 1 (pagesize 4096)))
-(module (memory 1 (pagesize 8192)))
-(module (memory 1 (pagesize 16384)))
-(module (memory 1 (pagesize 32768)))
 (module (memory 1 (pagesize 65536)))
 
 ;; Check them all again with maximums specified.
 (module (memory 1 2 (pagesize 1)))
-(module (memory 1 2 (pagesize 2)))
-(module (memory 1 2 (pagesize 4)))
-(module (memory 1 2 (pagesize 8)))
-(module (memory 1 2 (pagesize 16)))
-(module (memory 1 2 (pagesize 32)))
-(module (memory 1 2 (pagesize 64)))
-(module (memory 1 2 (pagesize 128)))
-(module (memory 1 2 (pagesize 256)))
-(module (memory 1 2 (pagesize 512)))
-(module (memory 1 2 (pagesize 1024)))
-(module (memory 1 2 (pagesize 2048)))
-(module (memory 1 2 (pagesize 4096)))
-(module (memory 1 2 (pagesize 8192)))
-(module (memory 1 2 (pagesize 16384)))
-(module (memory 1 2 (pagesize 32768)))
 (module (memory 1 2 (pagesize 65536)))
 
 ;; Check the behavior of memories with page size 1.
@@ -70,40 +40,6 @@
 (assert_return (invoke "load" (i32.const 131071)) (i32.const 1))
 (assert_trap (invoke "load" (i32.const 131072)) "out of bounds memory access")
 
-;; Check the behavior of memories with page size 4.
-(module
-  (memory 0 (pagesize 4))
-  (func (export "size") (result i32)
-    memory.size
-  )
-  (func (export "grow") (param i32) (result i32)
-    (memory.grow (local.get 0))
-  )
-  (func (export "load") (param i32) (result i32)
-    (i32.load (local.get 0))
-  )
-  (func (export "store") (param i32 i32)
-    (i32.store (local.get 0) (local.get 1))
-  )
-)
-
-(assert_return (invoke "size") (i32.const 0))
-(assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access")
-
-(assert_return (invoke "grow" (i32.const 65536)) (i32.const 0))
-(assert_return (invoke "size") (i32.const 65536))
-(assert_return (invoke "load" (i32.const 262143)) (i32.const 0))
-(assert_return (invoke "store" (i32.const 262143) (i32.const 1)))
-(assert_return (invoke "load" (i32.const 262143)) (i32.const 1))
-(assert_trap (invoke "load" (i32.const 262144)) "out of bounds memory access")
-
-(assert_return (invoke "grow" (i32.const 65536)) (i32.const 65536))
-(assert_return (invoke "size") (i32.const 131072))
-(assert_return (invoke "load" (i32.const 524287)) (i32.const 0))
-(assert_return (invoke "store" (i32.const 524287) (i32.const 1)))
-(assert_return (invoke "load" (i32.const 524287)) (i32.const 1))
-(assert_trap (invoke "load" (i32.const 524288)) "out of bounds memory access")
-
 ;; Although smaller page sizes let us get to memories larger than 2**16 pages,
 ;; we can't do that with the default page size, even if we explicitly state it
 ;; as a custom page size.
@@ -116,3 +52,37 @@
 (assert_return (invoke "size") (i32.const 0))
 (assert_return (invoke "grow" (i32.const 65537)) (i32.const -1))
 (assert_return (invoke "size") (i32.const 0))
+
+;; Can copy between memories of different page sizes.
+(module
+  (memory $small 10 (pagesize 1))
+  (memory $large 1 (pagesize 65536))
+
+  (data (memory $small) (i32.const 0) "\11\22\33\44")
+  (data (memory $large) (i32.const 0) "\55\66\77\88")
+
+  (func (export "copy-small-to-large") (param i32 i32 i32)
+    (memory.copy $small $large (local.get 0) (local.get 1) (local.get 2))
+  )
+
+  (func (export "copy-large-to-small") (param i32 i32 i32)
+    (memory.copy $large $small (local.get 0) (local.get 1) (local.get 2))
+  )
+
+  (func (export "load8-small") (param i32) (result i32)
+    (i32.load8_u (local.get 0))
+  )
+
+  (func (export "load8-large") (param i32) (result i32)
+    (i32.load8_u (local.get 0))
+  )
+)
+
+(assert_return (invoke "copy-small-to-large") (i32.const 0) (i32.const 2) (i32.const 6))
+(assert_return (invoke "load8-large") (i32.const 6) (i32.const 0x11))
+(assert_return (invoke "load8-large") (i32.const 7) (i32.const 0x22))
+
+(assert_return (invoke "copy-large-to-small") (i32.const 1) (i32.const 3) (i32.const 4))
+(assert_return (invoke "load8-large") (i32.const 4) (i32.const 0x66))
+(assert_return (invoke "load8-large") (i32.const 5) (i32.const 0x77))
+(assert_return (invoke "load8-large") (i32.const 6) (i32.const 0x88))
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes-invalid.wast.json b/tests/snapshots/local/custom-page-sizes/custom-page-sizes-invalid.wast.json
index 148d28e8..4ce8847b 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes-invalid.wast.json
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes-invalid.wast.json
@@ -3,24 +3,129 @@
   "commands": [
     {
       "type": "assert_malformed",
-      "line": 2,
+      "line": 3,
       "filename": "custom-page-sizes-invalid.0.wat",
       "text": "invalid custom page size",
       "module_type": "text"
     },
     {
       "type": "assert_invalid",
-      "line": 8,
+      "line": 9,
       "filename": "custom-page-sizes-invalid.1.wasm",
       "text": "invalid custom page size",
       "module_type": "binary"
     },
     {
-      "type": "assert_malformed",
-      "line": 15,
+      "type": "assert_invalid",
+      "line": 13,
       "filename": "custom-page-sizes-invalid.2.wasm",
       "text": "invalid custom page size",
       "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 17,
+      "filename": "custom-page-sizes-invalid.3.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 21,
+      "filename": "custom-page-sizes-invalid.4.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 25,
+      "filename": "custom-page-sizes-invalid.5.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 29,
+      "filename": "custom-page-sizes-invalid.6.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 33,
+      "filename": "custom-page-sizes-invalid.7.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 37,
+      "filename": "custom-page-sizes-invalid.8.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 41,
+      "filename": "custom-page-sizes-invalid.9.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 45,
+      "filename": "custom-page-sizes-invalid.10.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 49,
+      "filename": "custom-page-sizes-invalid.11.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 53,
+      "filename": "custom-page-sizes-invalid.12.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 57,
+      "filename": "custom-page-sizes-invalid.13.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 61,
+      "filename": "custom-page-sizes-invalid.14.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 65,
+      "filename": "custom-page-sizes-invalid.15.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 71,
+      "filename": "custom-page-sizes-invalid.16.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_malformed",
+      "line": 78,
+      "filename": "custom-page-sizes-invalid.17.wasm",
+      "text": "invalid custom page size",
+      "module_type": "binary"
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast.json b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast.json
index cb8a60cb..4efa263e 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast.json
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast.json
@@ -11,174 +11,24 @@
       "line": 3,
       "filename": "custom-page-sizes.1.wasm"
     },
-    {
-      "type": "module",
-      "line": 4,
-      "filename": "custom-page-sizes.2.wasm"
-    },
-    {
-      "type": "module",
-      "line": 5,
-      "filename": "custom-page-sizes.3.wasm"
-    },
     {
       "type": "module",
       "line": 6,
-      "filename": "custom-page-sizes.4.wasm"
+      "filename": "custom-page-sizes.2.wasm"
     },
     {
       "type": "module",
       "line": 7,
-      "filename": "custom-page-sizes.5.wasm"
-    },
-    {
-      "type": "module",
-      "line": 8,
-      "filename": "custom-page-sizes.6.wasm"
-    },
-    {
-      "type": "module",
-      "line": 9,
-      "filename": "custom-page-sizes.7.wasm"
+      "filename": "custom-page-sizes.3.wasm"
     },
     {
       "type": "module",
       "line": 10,
-      "filename": "custom-page-sizes.8.wasm"
-    },
-    {
-      "type": "module",
-      "line": 11,
-      "filename": "custom-page-sizes.9.wasm"
-    },
-    {
-      "type": "module",
-      "line": 12,
-      "filename": "custom-page-sizes.10.wasm"
-    },
-    {
-      "type": "module",
-      "line": 13,
-      "filename": "custom-page-sizes.11.wasm"
-    },
-    {
-      "type": "module",
-      "line": 14,
-      "filename": "custom-page-sizes.12.wasm"
-    },
-    {
-      "type": "module",
-      "line": 15,
-      "filename": "custom-page-sizes.13.wasm"
-    },
-    {
-      "type": "module",
-      "line": 16,
-      "filename": "custom-page-sizes.14.wasm"
-    },
-    {
-      "type": "module",
-      "line": 17,
-      "filename": "custom-page-sizes.15.wasm"
-    },
-    {
-      "type": "module",
-      "line": 18,
-      "filename": "custom-page-sizes.16.wasm"
-    },
-    {
-      "type": "module",
-      "line": 21,
-      "filename": "custom-page-sizes.17.wasm"
-    },
-    {
-      "type": "module",
-      "line": 22,
-      "filename": "custom-page-sizes.18.wasm"
-    },
-    {
-      "type": "module",
-      "line": 23,
-      "filename": "custom-page-sizes.19.wasm"
-    },
-    {
-      "type": "module",
-      "line": 24,
-      "filename": "custom-page-sizes.20.wasm"
-    },
-    {
-      "type": "module",
-      "line": 25,
-      "filename": "custom-page-sizes.21.wasm"
-    },
-    {
-      "type": "module",
-      "line": 26,
-      "filename": "custom-page-sizes.22.wasm"
-    },
-    {
-      "type": "module",
-      "line": 27,
-      "filename": "custom-page-sizes.23.wasm"
-    },
-    {
-      "type": "module",
-      "line": 28,
-      "filename": "custom-page-sizes.24.wasm"
-    },
-    {
-      "type": "module",
-      "line": 29,
-      "filename": "custom-page-sizes.25.wasm"
-    },
-    {
-      "type": "module",
-      "line": 30,
-      "filename": "custom-page-sizes.26.wasm"
-    },
-    {
-      "type": "module",
-      "line": 31,
-      "filename": "custom-page-sizes.27.wasm"
-    },
-    {
-      "type": "module",
-      "line": 32,
-      "filename": "custom-page-sizes.28.wasm"
-    },
-    {
-      "type": "module",
-      "line": 33,
-      "filename": "custom-page-sizes.29.wasm"
-    },
-    {
-      "type": "module",
-      "line": 34,
-      "filename": "custom-page-sizes.30.wasm"
-    },
-    {
-      "type": "module",
-      "line": 35,
-      "filename": "custom-page-sizes.31.wasm"
-    },
-    {
-      "type": "module",
-      "line": 36,
-      "filename": "custom-page-sizes.32.wasm"
-    },
-    {
-      "type": "module",
-      "line": 37,
-      "filename": "custom-page-sizes.33.wasm"
-    },
-    {
-      "type": "module",
-      "line": 40,
-      "filename": "custom-page-sizes.34.wasm"
+      "filename": "custom-page-sizes.4.wasm"
     },
     {
       "type": "assert_return",
-      "line": 56,
+      "line": 26,
       "action": {
         "type": "invoke",
         "field": "size",
@@ -193,7 +43,7 @@
     },
     {
       "type": "assert_trap",
-      "line": 57,
+      "line": 27,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -208,7 +58,7 @@
     },
     {
       "type": "assert_return",
-      "line": 59,
+      "line": 29,
       "action": {
         "type": "invoke",
         "field": "grow",
@@ -228,7 +78,7 @@
     },
     {
       "type": "assert_return",
-      "line": 60,
+      "line": 30,
       "action": {
         "type": "invoke",
         "field": "size",
@@ -243,7 +93,7 @@
     },
     {
       "type": "assert_return",
-      "line": 61,
+      "line": 31,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -263,7 +113,7 @@
     },
     {
       "type": "assert_return",
-      "line": 62,
+      "line": 32,
       "action": {
         "type": "invoke",
         "field": "store",
@@ -282,7 +132,7 @@
     },
     {
       "type": "assert_return",
-      "line": 63,
+      "line": 33,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -302,7 +152,7 @@
     },
     {
       "type": "assert_trap",
-      "line": 64,
+      "line": 34,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -317,7 +167,7 @@
     },
     {
       "type": "assert_return",
-      "line": 66,
+      "line": 36,
       "action": {
         "type": "invoke",
         "field": "grow",
@@ -337,7 +187,7 @@
     },
     {
       "type": "assert_return",
-      "line": 67,
+      "line": 37,
       "action": {
         "type": "invoke",
         "field": "size",
@@ -352,7 +202,7 @@
     },
     {
       "type": "assert_return",
-      "line": 68,
+      "line": 38,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -372,7 +222,7 @@
     },
     {
       "type": "assert_return",
-      "line": 69,
+      "line": 39,
       "action": {
         "type": "invoke",
         "field": "store",
@@ -391,7 +241,7 @@
     },
     {
       "type": "assert_return",
-      "line": 70,
+      "line": 40,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -411,7 +261,7 @@
     },
     {
       "type": "assert_trap",
-      "line": 71,
+      "line": 41,
       "action": {
         "type": "invoke",
         "field": "load",
@@ -426,12 +276,12 @@
     },
     {
       "type": "module",
-      "line": 74,
-      "filename": "custom-page-sizes.35.wasm"
+      "line": 46,
+      "filename": "custom-page-sizes.5.wasm"
     },
     {
       "type": "assert_return",
-      "line": 90,
+      "line": 52,
       "action": {
         "type": "invoke",
         "field": "size",
@@ -444,69 +294,34 @@
         }
       ]
     },
-    {
-      "type": "assert_trap",
-      "line": 91,
-      "action": {
-        "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "0"
-          }
-        ]
-      },
-      "text": "out of bounds memory access"
-    },
     {
       "type": "assert_return",
-      "line": 93,
+      "line": 53,
       "action": {
         "type": "invoke",
         "field": "grow",
         "args": [
           {
             "type": "i32",
-            "value": "65536"
+            "value": "65537"
           }
         ]
       },
       "expected": [
         {
           "type": "i32",
-          "value": "0"
+          "value": "-1"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 94,
+      "line": 54,
       "action": {
         "type": "invoke",
         "field": "size",
         "args": []
       },
-      "expected": [
-        {
-          "type": "i32",
-          "value": "65536"
-        }
-      ]
-    },
-    {
-      "type": "assert_return",
-      "line": 95,
-      "action": {
-        "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "262143"
-          }
-        ]
-      },
       "expected": [
         {
           "type": "i32",
@@ -515,220 +330,148 @@
       ]
     },
     {
-      "type": "assert_return",
-      "line": 96,
-      "action": {
-        "type": "invoke",
-        "field": "store",
-        "args": [
-          {
-            "type": "i32",
-            "value": "262143"
-          },
-          {
-            "type": "i32",
-            "value": "1"
-          }
-        ]
-      },
-      "expected": []
+      "type": "module",
+      "line": 57,
+      "filename": "custom-page-sizes.6.wasm"
     },
     {
       "type": "assert_return",
-      "line": 97,
+      "line": 81,
       "action": {
         "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "262143"
-          }
-        ]
+        "field": "copy-small-to-large",
+        "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "1"
-        }
-      ]
-    },
-    {
-      "type": "assert_trap",
-      "line": 98,
-      "action": {
-        "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "262144"
-          }
-        ]
-      },
-      "text": "out of bounds memory access"
-    },
-    {
-      "type": "assert_return",
-      "line": 100,
-      "action": {
-        "type": "invoke",
-        "field": "grow",
-        "args": [
-          {
-            "type": "i32",
-            "value": "65536"
-          }
-        ]
-      },
-      "expected": [
+          "value": "0"
+        },
         {
           "type": "i32",
-          "value": "65536"
+          "value": "2"
+        },
+        {
+          "type": "i32",
+          "value": "6"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 101,
+      "line": 82,
       "action": {
         "type": "invoke",
-        "field": "size",
+        "field": "load8-large",
         "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "131072"
+          "value": "6"
+        },
+        {
+          "type": "i32",
+          "value": "17"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 102,
+      "line": 83,
       "action": {
         "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "524287"
-          }
-        ]
+        "field": "load8-large",
+        "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "0"
+          "value": "7"
+        },
+        {
+          "type": "i32",
+          "value": "34"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 103,
+      "line": 85,
       "action": {
         "type": "invoke",
-        "field": "store",
-        "args": [
-          {
-            "type": "i32",
-            "value": "524287"
-          },
-          {
-            "type": "i32",
-            "value": "1"
-          }
-        ]
-      },
-      "expected": []
-    },
-    {
-      "type": "assert_return",
-      "line": 104,
-      "action": {
-        "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "524287"
-          }
-        ]
+        "field": "copy-large-to-small",
+        "args": []
       },
       "expected": [
         {
           "type": "i32",
           "value": "1"
+        },
+        {
+          "type": "i32",
+          "value": "3"
+        },
+        {
+          "type": "i32",
+          "value": "4"
         }
       ]
     },
-    {
-      "type": "assert_trap",
-      "line": 105,
-      "action": {
-        "type": "invoke",
-        "field": "load",
-        "args": [
-          {
-            "type": "i32",
-            "value": "524288"
-          }
-        ]
-      },
-      "text": "out of bounds memory access"
-    },
-    {
-      "type": "module",
-      "line": 110,
-      "filename": "custom-page-sizes.36.wasm"
-    },
     {
       "type": "assert_return",
-      "line": 116,
+      "line": 86,
       "action": {
         "type": "invoke",
-        "field": "size",
+        "field": "load8-large",
         "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "0"
+          "value": "4"
+        },
+        {
+          "type": "i32",
+          "value": "102"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 117,
+      "line": 87,
       "action": {
         "type": "invoke",
-        "field": "grow",
-        "args": [
-          {
-            "type": "i32",
-            "value": "65537"
-          }
-        ]
+        "field": "load8-large",
+        "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "-1"
+          "value": "5"
+        },
+        {
+          "type": "i32",
+          "value": "119"
         }
       ]
     },
     {
       "type": "assert_return",
-      "line": 118,
+      "line": 88,
       "action": {
         "type": "invoke",
-        "field": "size",
+        "field": "load8-large",
         "args": []
       },
       "expected": [
         {
           "type": "i32",
-          "value": "0"
+          "value": "6"
+        },
+        {
+          "type": "i32",
+          "value": "136"
         }
       ]
     }
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print
index d6497899..c263f183 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print
@@ -1,3 +1,3 @@
 (module
-  (memory (;0;) 1(pagesize 0x2))
+  (memory (;0;) 1(pagesize 0x10000))
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/10.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/10.print
deleted file mode 100644
index 95c594b2..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/10.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x400))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/11.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/11.print
deleted file mode 100644
index 8733c887..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/11.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x800))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/12.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/12.print
deleted file mode 100644
index 7aa6bfca..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/12.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x1000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/13.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/13.print
deleted file mode 100644
index 9e81289b..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/13.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x2000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/14.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/14.print
deleted file mode 100644
index e7992c88..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/14.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x4000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/15.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/15.print
deleted file mode 100644
index 95c30b5b..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/15.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x8000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/16.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/16.print
deleted file mode 100644
index c263f183..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/16.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x10000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/17.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/17.print
deleted file mode 100644
index b28b4479..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/17.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x1))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/18.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/18.print
deleted file mode 100644
index fb6f4167..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/18.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x2))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print
index 4ef285e5..2f377e5a 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print
@@ -1,3 +1,9 @@
 (module
-  (memory (;0;) 1 2(pagesize 0x4))
+  (type (;0;) (func (param i32) (result i32)))
+  (func (;0;) (type 0) (param i32) (result i32)
+    local.get 0
+    memory.grow
+  )
+  (memory (;0;) 0(pagesize 0x10000))
+  (export "grow" (func 0))
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print
index 4b597335..b28b4479 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print
@@ -1,3 +1,3 @@
 (module
-  (memory (;0;) 1(pagesize 0x4))
+  (memory (;0;) 1 2(pagesize 0x1))
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/20.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/20.print
deleted file mode 100644
index 856b94ba..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/20.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x8))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/21.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/21.print
deleted file mode 100644
index 6e89c150..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/21.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x10))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/22.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/22.print
deleted file mode 100644
index 7a208af4..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/22.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x20))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print
index f71aeb66..1c3b7326 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print
@@ -1,3 +1,32 @@
 (module
-  (memory (;0;) 1 2(pagesize 0x40))
+  (type (;0;) (func (param i32 i32 i32)))
+  (type (;1;) (func (param i32) (result i32)))
+  (func (;0;) (type 0) (param i32 i32 i32)
+    local.get 0
+    local.get 1
+    local.get 2
+    memory.copy $small $large
+  )
+  (func (;1;) (type 0) (param i32 i32 i32)
+    local.get 0
+    local.get 1
+    local.get 2
+    memory.copy $large $small
+  )
+  (func (;2;) (type 1) (param i32) (result i32)
+    local.get 0
+    i32.load8_u
+  )
+  (func (;3;) (type 1) (param i32) (result i32)
+    local.get 0
+    i32.load8_u
+  )
+  (memory $small (;0;) 10(pagesize 0x1))
+  (memory $large (;1;) 1(pagesize 0x10000))
+  (export "copy-small-to-large" (func 0))
+  (export "copy-large-to-small" (func 1))
+  (export "load8-small" (func 2))
+  (export "load8-large" (func 3))
+  (data (;0;) (i32.const 0) "\11\223D")
+  (data (;1;) (memory $large) (i32.const 0) "Ufw\88")
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/24.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/24.print
deleted file mode 100644
index ff0f9a97..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/24.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x80))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/25.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/25.print
deleted file mode 100644
index 3cf7a788..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/25.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x100))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/26.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/26.print
deleted file mode 100644
index d42f2812..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/26.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x200))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/27.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/27.print
deleted file mode 100644
index 0c210e31..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/27.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x400))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/28.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/28.print
deleted file mode 100644
index 039df3ae..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/28.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x800))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/29.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/29.print
deleted file mode 100644
index 1f62101a..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/29.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x1000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print
index f163e660..afb7ad5c 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print
@@ -1,3 +1,3 @@
 (module
-  (memory (;0;) 1(pagesize 0x8))
+  (memory (;0;) 1 2(pagesize 0x10000))
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/30.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/30.print
deleted file mode 100644
index 79d258eb..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/30.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x2000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/31.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/31.print
deleted file mode 100644
index c1d9489a..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/31.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x4000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/32.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/32.print
deleted file mode 100644
index e7d337a3..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/32.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x8000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/33.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/33.print
deleted file mode 100644
index afb7ad5c..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/33.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1 2(pagesize 0x10000))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/34.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/34.print
deleted file mode 100644
index 388265c2..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/34.print
+++ /dev/null
@@ -1,26 +0,0 @@
-(module
-  (type (;0;) (func (result i32)))
-  (type (;1;) (func (param i32) (result i32)))
-  (type (;2;) (func (param i32 i32)))
-  (func (;0;) (type 0) (result i32)
-    memory.size
-  )
-  (func (;1;) (type 1) (param i32) (result i32)
-    local.get 0
-    memory.grow
-  )
-  (func (;2;) (type 1) (param i32) (result i32)
-    local.get 0
-    i32.load8_u
-  )
-  (func (;3;) (type 2) (param i32 i32)
-    local.get 0
-    local.get 1
-    i32.store
-  )
-  (memory (;0;) 0(pagesize 0x1))
-  (export "size" (func 0))
-  (export "grow" (func 1))
-  (export "load" (func 2))
-  (export "store" (func 3))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print
index 1fe3d04b..388265c2 100644
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print
+++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print
@@ -1,3 +1,26 @@
 (module
-  (memory (;0;) 1(pagesize 0x10))
+  (type (;0;) (func (result i32)))
+  (type (;1;) (func (param i32) (result i32)))
+  (type (;2;) (func (param i32 i32)))
+  (func (;0;) (type 0) (result i32)
+    memory.size
+  )
+  (func (;1;) (type 1) (param i32) (result i32)
+    local.get 0
+    memory.grow
+  )
+  (func (;2;) (type 1) (param i32) (result i32)
+    local.get 0
+    i32.load8_u
+  )
+  (func (;3;) (type 2) (param i32 i32)
+    local.get 0
+    local.get 1
+    i32.store
+  )
+  (memory (;0;) 0(pagesize 0x1))
+  (export "size" (func 0))
+  (export "grow" (func 1))
+  (export "load" (func 2))
+  (export "store" (func 3))
 )
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/49.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/49.print
deleted file mode 100644
index 758f2d34..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/49.print
+++ /dev/null
@@ -1,26 +0,0 @@
-(module
-  (type (;0;) (func (result i32)))
-  (type (;1;) (func (param i32) (result i32)))
-  (type (;2;) (func (param i32 i32)))
-  (func (;0;) (type 0) (result i32)
-    memory.size
-  )
-  (func (;1;) (type 1) (param i32) (result i32)
-    local.get 0
-    memory.grow
-  )
-  (func (;2;) (type 1) (param i32) (result i32)
-    local.get 0
-    i32.load
-  )
-  (func (;3;) (type 2) (param i32 i32)
-    local.get 0
-    local.get 1
-    i32.store
-  )
-  (memory (;0;) 0(pagesize 0x4))
-  (export "size" (func 0))
-  (export "grow" (func 1))
-  (export "load" (func 2))
-  (export "store" (func 3))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/5.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/5.print
deleted file mode 100644
index a210ac4b..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/5.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x20))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/6.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/6.print
deleted file mode 100644
index 4c98bf43..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/6.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x40))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/64.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/64.print
deleted file mode 100644
index 2f377e5a..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/64.print
+++ /dev/null
@@ -1,9 +0,0 @@
-(module
-  (type (;0;) (func (param i32) (result i32)))
-  (func (;0;) (type 0) (param i32) (result i32)
-    local.get 0
-    memory.grow
-  )
-  (memory (;0;) 0(pagesize 0x10000))
-  (export "grow" (func 0))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/7.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/7.print
deleted file mode 100644
index d82edd6d..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/7.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x80))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/8.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/8.print
deleted file mode 100644
index daf57e3d..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/8.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x100))
-)
diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/9.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/9.print
deleted file mode 100644
index 1a6096b4..00000000
--- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/9.print
+++ /dev/null
@@ -1,3 +0,0 @@
-(module
-  (memory (;0;) 1(pagesize 0x200))
-)