Skip to content

Commit 6484e0b

Browse files
authored
Fix subtype check of linear memories to look at page sizes (bytecodealliance#2477)
* Fix subtype check of linear memories to look at page sizes This commit fixes validation of `MemoryType` in `wasmparser` to ensure that the page size of two linear memories are the same for them to be considered subtypes of one another. This fixes an issue where components could accidentally use 1-byte-page memories for lifting/lowering which isn't allowed by the component model right now. The component model currently has a restriction that all memories must be a subtype of `(memory 0)`, or must have a 64k page size. * Fix bless'd files
1 parent b960a87 commit 6484e0b

13 files changed

Lines changed: 243 additions & 19 deletions

File tree

crates/wasm-encoder/src/core/memories.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,20 @@ impl Encode for MemoryType {
114114
}
115115
}
116116
}
117+
118+
impl MemoryType {
119+
/// Returns the actual log2 of the page size of this linear memory,
120+
/// returning the default if the memory itself doesn't specify.
121+
pub const fn page_size_log2(&self) -> u32 {
122+
const DEFAULT_WASM_PAGE_SIZE_LOG2: u32 = 16;
123+
match self.page_size_log2 {
124+
Some(log2) => log2,
125+
None => DEFAULT_WASM_PAGE_SIZE_LOG2,
126+
}
127+
}
128+
129+
/// Returns the page size, in bytes, of this linear memory.
130+
pub const fn page_size(&self) -> u32 {
131+
1 << self.page_size_log2()
132+
}
133+
}

crates/wasm-smith/src/core.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,7 +2916,7 @@ impl Module {
29162916

29172917
// Interesting values related to memory bounds.
29182918
for m in self.memories.iter() {
2919-
let min = m.minimum.saturating_mul(crate::page_size(m).into());
2919+
let min = m.minimum.saturating_mul(m.page_size().into());
29202920
interesting(min);
29212921
for i in 0..5 {
29222922
if let Some(x) = min.checked_add(1 << i) {
@@ -2928,7 +2928,7 @@ impl Module {
29282928
}
29292929

29302930
if let Some(max) = m.maximum {
2931-
let max = max.saturating_mul(crate::page_size(m).into());
2931+
let max = max.saturating_mul(m.page_size().into());
29322932
interesting(max);
29332933
for i in 0..5 {
29342934
if let Some(x) = max.checked_add(1 << i) {

crates/wasm-smith/src/core/code_builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5367,10 +5367,10 @@ fn memory_offset(u: &mut Unstructured, module: &Module, memory_index: u32) -> Re
53675367
let memory_type = &module.memories[memory_index as usize];
53685368
let min = memory_type
53695369
.minimum
5370-
.saturating_mul(crate::page_size(memory_type).into());
5370+
.saturating_mul(memory_type.page_size().into());
53715371
let max = memory_type
53725372
.maximum
5373-
.map(|max| max.saturating_mul(crate::page_size(memory_type).into()))
5373+
.map(|max| max.saturating_mul(memory_type.page_size().into()))
53745374
.unwrap_or(u64::MAX);
53755375

53765376
let (min, max, true_max) = match (memory_type.memory64, module.config.disallow_traps) {

crates/wasm-smith/src/core/code_builder/no_traps.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ pub(crate) fn load<'a>(
3737
// []
3838
insts.push(Instruction::MemorySize(memarg.memory_index));
3939
// [mem_size_in_pages:address_type]
40-
insts.push(int_const_inst(
41-
address_type,
42-
crate::page_size(memory).into(),
43-
));
40+
insts.push(int_const_inst(address_type, memory.page_size().into()));
4441
// [mem_size_in_pages:address_type wasm_page_size:address_type]
4542
insts.push(int_mul_inst(address_type));
4643
// [mem_size_in_bytes:address_type]
@@ -119,10 +116,7 @@ pub(crate) fn store<'a>(
119116
// []
120117
insts.push(Instruction::MemorySize(memarg.memory_index));
121118
// [mem_size_in_pages:address_type]
122-
insts.push(int_const_inst(
123-
address_type,
124-
crate::page_size(memory).into(),
125-
));
119+
insts.push(int_const_inst(address_type, memory.page_size().into()));
126120
// [mem_size_in_pages:address_type wasm_page_size:address_type]
127121
insts.push(int_mul_inst(address_type));
128122
// [mem_size_in_bytes:address_type]

crates/wasm-smith/src/lib.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,10 @@ use arbitrary::{Result, Unstructured};
6868
pub use component::Component;
6969
pub use config::{Config, MemoryOffsetChoices};
7070
use std::{collections::HashSet, fmt::Write, str};
71-
use wasm_encoder::MemoryType;
7271

7372
#[doc(hidden)]
7473
pub use config::InternalOptionalConfig;
7574

76-
pub(crate) fn page_size(mem: &MemoryType) -> u32 {
77-
const DEFAULT_WASM_PAGE_SIZE_LOG2: u32 = 16;
78-
1 << mem.page_size_log2.unwrap_or(DEFAULT_WASM_PAGE_SIZE_LOG2)
79-
}
80-
8175
/// Do something an arbitrary number of times.
8276
///
8377
/// The callback can return `false` to exit the loop early.

crates/wasmparser/src/readers/core/types.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1995,13 +1995,28 @@ pub struct MemoryType {
19951995

19961996
impl MemoryType {
19971997
/// Gets the index type for the memory.
1998-
pub fn index_type(&self) -> ValType {
1998+
pub const fn index_type(&self) -> ValType {
19991999
if self.memory64 {
20002000
ValType::I64
20012001
} else {
20022002
ValType::I32
20032003
}
20042004
}
2005+
2006+
/// Returns the actual log2 of the page size of this linear memory,
2007+
/// returning the default if the memory itself doesn't specify.
2008+
pub const fn page_size_log2(&self) -> u32 {
2009+
const DEFAULT_WASM_PAGE_SIZE_LOG2: u32 = 16;
2010+
match self.page_size_log2 {
2011+
Some(log2) => log2,
2012+
None => DEFAULT_WASM_PAGE_SIZE_LOG2,
2013+
}
2014+
}
2015+
2016+
/// Returns the page size, in bytes, of this linear memory.
2017+
pub const fn page_size(&self) -> u32 {
2018+
1 << self.page_size_log2()
2019+
}
20052020
}
20062021

20072022
/// Represents a global's type.

crates/wasmparser/src/validator/component_types.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,6 +3670,9 @@ impl<'a> SubtypeCx<'a> {
36703670
if a.memory64 != b.memory64 {
36713671
bail!(offset, "mismatch in index type used for memories")
36723672
}
3673+
if a.page_size_log2() != b.page_size_log2() {
3674+
bail!(offset, "mismatch in page size for memories")
3675+
}
36733676
if limits_match!(a, b) {
36743677
Ok(())
36753678
} else {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
;; RUN: wast --assert default --snapshot tests/snapshots % -f custom-page-sizes
2+
3+
;; explicitly specifying the page size is ok
4+
(component
5+
(import "f" (func $f (param "x" string)))
6+
(core module $m
7+
(memory (export "m") 1 (pagesize 65536))
8+
)
9+
(core instance $i (instantiate $m))
10+
(core func (canon lower (func $f) (memory $i "m")))
11+
)
12+
13+
;; currently the component model requires all memories are a subtype of
14+
;; `(memory 0)`, AKA no compat with custom page sizes. This has not yet been
15+
;; relaxed at the spec level.
16+
(assert_invalid
17+
(component
18+
(import "f" (func $f (param "x" string)))
19+
(core module $m
20+
(memory (export "m") 1 (pagesize 1))
21+
)
22+
(core instance $i (instantiate $m))
23+
(core func (canon lower (func $f) (memory $i "m")))
24+
)
25+
"mismatch in page size for memories"
26+
)
27+
28+
;; subtyping works with custom-page-sizes
29+
(component
30+
(core module $a (memory (export "m") 1 (pagesize 65536)))
31+
(core module $b (import "a" "m" (memory 1 (pagesize 65536))))
32+
(core instance $a (instantiate $a))
33+
(core instance $b (instantiate $b (with "a" (instance $a))))
34+
)
35+
36+
(component
37+
(core module $a (memory (export "m") 1 (pagesize 65536)))
38+
(core module $b (import "a" "m" (memory 1)))
39+
(core instance $a (instantiate $a))
40+
(core instance $b (instantiate $b (with "a" (instance $a))))
41+
)
42+
43+
(component
44+
(core module $a (memory (export "m") 1))
45+
(core module $b (import "a" "m" (memory 1 (pagesize 65536))))
46+
(core instance $a (instantiate $a))
47+
(core instance $b (instantiate $b (with "a" (instance $a))))
48+
)
49+
50+
(assert_invalid
51+
(component
52+
(core module $a (memory (export "m") 1 (pagesize 1)))
53+
(core module $b (import "a" "m" (memory 1 (pagesize 65536))))
54+
(core instance $a (instantiate $a))
55+
(core instance $b (instantiate $b (with "a" (instance $a))))
56+
)
57+
"mismatch in page size for memories")
58+
59+
(assert_invalid
60+
(component
61+
(core module $a (memory (export "m") 1 (pagesize 65536)))
62+
(core module $b (import "a" "m" (memory 1 (pagesize 1))))
63+
(core instance $a (instantiate $a))
64+
(core instance $b (instantiate $b (with "a" (instance $a))))
65+
)
66+
"mismatch in page size for memories")
67+
68+
(assert_invalid
69+
(component
70+
(core module $a (memory (export "m") 1 (pagesize 1)))
71+
(core module $b (import "a" "m" (memory 1)))
72+
(core instance $a (instantiate $a))
73+
(core instance $b (instantiate $b (with "a" (instance $a))))
74+
)
75+
"mismatch in page size for memories")
76+
77+
(assert_invalid
78+
(component
79+
(core module $a (memory (export "m") 1))
80+
(core module $b (import "a" "m" (memory 1 (pagesize 1))))
81+
(core instance $a (instantiate $a))
82+
(core instance $b (instantiate $b (with "a" (instance $a))))
83+
)
84+
"mismatch in page size for memories")
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"source_filename": "tests/cli/component-model/custom-page-sizes.wast",
3+
"commands": [
4+
{
5+
"type": "module",
6+
"line": 4,
7+
"filename": "custom-page-sizes.0.wasm",
8+
"module_type": "binary"
9+
},
10+
{
11+
"type": "assert_invalid",
12+
"line": 17,
13+
"filename": "custom-page-sizes.1.wasm",
14+
"module_type": "binary",
15+
"text": "mismatch in page size for memories"
16+
},
17+
{
18+
"type": "module",
19+
"line": 29,
20+
"filename": "custom-page-sizes.2.wasm",
21+
"module_type": "binary"
22+
},
23+
{
24+
"type": "module",
25+
"line": 36,
26+
"filename": "custom-page-sizes.3.wasm",
27+
"module_type": "binary"
28+
},
29+
{
30+
"type": "module",
31+
"line": 43,
32+
"filename": "custom-page-sizes.4.wasm",
33+
"module_type": "binary"
34+
},
35+
{
36+
"type": "assert_invalid",
37+
"line": 51,
38+
"filename": "custom-page-sizes.5.wasm",
39+
"module_type": "binary",
40+
"text": "mismatch in page size for memories"
41+
},
42+
{
43+
"type": "assert_invalid",
44+
"line": 60,
45+
"filename": "custom-page-sizes.6.wasm",
46+
"module_type": "binary",
47+
"text": "mismatch in page size for memories"
48+
},
49+
{
50+
"type": "assert_invalid",
51+
"line": 69,
52+
"filename": "custom-page-sizes.7.wasm",
53+
"module_type": "binary",
54+
"text": "mismatch in page size for memories"
55+
},
56+
{
57+
"type": "assert_invalid",
58+
"line": 78,
59+
"filename": "custom-page-sizes.8.wasm",
60+
"module_type": "binary",
61+
"text": "mismatch in page size for memories"
62+
}
63+
]
64+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(component
2+
(type (;0;) (func (param "x" string)))
3+
(import "f" (func $f (;0;) (type 0)))
4+
(core module $m (;0;)
5+
(memory (;0;) 1 (pagesize 0x10000))
6+
(export "m" (memory 0))
7+
)
8+
(core instance $i (;0;) (instantiate $m))
9+
(alias core export $i "m" (core memory (;0;)))
10+
(core func (;0;) (canon lower (func $f) (memory 0)))
11+
)

0 commit comments

Comments
 (0)