diff --git a/crates/wasm-shrink/src/lib.rs b/crates/wasm-shrink/src/lib.rs index 9ff2ae8063..63315f73a1 100755 --- a/crates/wasm-shrink/src/lib.rs +++ b/crates/wasm-shrink/src/lib.rs @@ -235,6 +235,7 @@ impl ShrinkRun { component_model: false, function_references: false, gc: false, + component_model_values: false, floats: true, memory_control: true, diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs index 0e0115a816..c63b9644c4 100644 --- a/crates/wasm-smith/tests/core.rs +++ b/crates/wasm-smith/tests/core.rs @@ -309,6 +309,7 @@ fn parser_features_from_config(config: &impl Config) -> WasmFeatures { function_references: false, memory_control: false, gc: false, + component_model_values: false, } } diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index 1ce37bf5a2..30526a58c6 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -254,6 +254,7 @@ fn define_benchmarks(c: &mut Criterion) { function_references: true, memory_control: true, gc: true, + component_model_values: true, }) } diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 6d964d47ce..48f404ff2a 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -247,6 +247,8 @@ pub struct WasmFeatures { pub memory_control: bool, /// The WebAssembly gc proposal pub gc: bool, + /// Support for the `value` type in the component model proposal. + pub component_model_values: bool, } impl WasmFeatures { @@ -336,6 +338,7 @@ impl Default for WasmFeatures { function_references: false, memory_control: false, gc: false, + component_model_values: false, // On-by-default features (phase 4 or greater). mutable_global: true, @@ -1062,11 +1065,11 @@ impl Validator { current.instances.reserve(count as usize); Ok(()) }, - |components, types, _, instance, offset| { + |components, types, features, instance, offset| { components .last_mut() .unwrap() - .add_instance(instance, types, offset) + .add_instance(instance, features, types, offset) }, ) } @@ -1082,8 +1085,8 @@ impl Validator { section, "alias", |_, _, _, _| Ok(()), // maximums checked via `add_alias` - |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { - ComponentState::add_alias(components, alias, types, offset) + |components, types, features, alias, offset| -> Result<(), BinaryReaderError> { + ComponentState::add_alias(components, alias, features, types, offset) }, ) } @@ -1181,6 +1184,7 @@ impl Validator { f.func_index, &f.arguments, f.results, + &self.features, &self.types, range.start, ) @@ -1197,11 +1201,11 @@ impl Validator { section, "import", |_, _, _, _| Ok(()), // add_import will check limits - |components, types, _, import, offset| { + |components, types, features, import, offset| { components .last_mut() .unwrap() - .add_import(import, types, offset) + .add_import(import, features, types, offset) }, ) } @@ -1228,12 +1232,13 @@ impl Validator { current.exports.reserve(count as usize); Ok(()) }, - |components, types, _, export, offset| { + |components, types, features, export, offset| { let current = components.last_mut().unwrap(); - let ty = current.export_to_entity_type(&export, types, offset)?; + let ty = current.export_to_entity_type(&export, features, types, offset)?; current.add_export( export.name, ty, + features, types, offset, false, /* checked above */ diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index da415a9070..a94aa6be2d 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -410,13 +410,15 @@ impl ComponentState { pub fn add_import( &mut self, import: crate::ComponentImport, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { - let mut entity = self.check_type_ref(&import.ty, types, offset)?; + let mut entity = self.check_type_ref(&import.ty, features, types, offset)?; self.add_entity( &mut entity, Some((import.name.as_str(), ExternKind::Import)), + features, types, offset, )?; @@ -437,6 +439,7 @@ impl ComponentState { &mut self, ty: &mut ComponentEntityType, name_and_kind: Option<(&str, ExternKind)>, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -464,6 +467,7 @@ impl ComponentState { (self.function_count(), MAX_WASM_FUNCTIONS, "functions") } ComponentEntityType::Value(ty) => { + self.check_value_support(features, offset)?; let value_used = match kind { Some(ExternKind::Import) | None => false, Some(ExternKind::Export) => true, @@ -868,6 +872,7 @@ impl ComponentState { &mut self, name: ComponentExternName<'_>, mut ty: ComponentEntityType, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, check_limit: bool, @@ -878,6 +883,7 @@ impl ComponentState { self.add_entity( &mut ty, Some((name.as_str(), ExternKind::Export)), + features, types, offset, )?; @@ -1037,6 +1043,7 @@ impl ComponentState { pub fn add_instance( &mut self, instance: crate::ComponentInstance, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1044,9 +1051,15 @@ impl ComponentState { crate::ComponentInstance::Instantiate { component_index, args, - } => self.instantiate_component(component_index, args.into_vec(), types, offset)?, + } => self.instantiate_component( + component_index, + args.into_vec(), + features, + types, + offset, + )?, crate::ComponentInstance::FromExports(exports) => { - self.instantiate_exports(exports.into_vec(), types, offset)? + self.instantiate_exports(exports.into_vec(), features, types, offset)? } }; @@ -1058,6 +1071,7 @@ impl ComponentState { pub fn add_alias( components: &mut [Self], alias: crate::ComponentAlias, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { @@ -1070,6 +1084,7 @@ impl ComponentState { instance_index, kind, name, + features, types, offset, ), @@ -1106,9 +1121,16 @@ impl ComponentState { func_index: u32, args: &[u32], results: u32, + features: &WasmFeatures, types: &TypeList, offset: usize, ) -> Result<()> { + if !features.component_model_values { + bail!( + offset, + "support for component model `value`s is not enabled" + ); + } if self.has_start { return Err(BinaryReaderError::new( "component cannot have more than one start function", @@ -1281,6 +1303,7 @@ impl ComponentState { fn check_type_ref( &mut self, ty: &ComponentTypeRef, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result { @@ -1302,6 +1325,7 @@ impl ComponentState { ComponentEntityType::Func(id) } ComponentTypeRef::Value(ty) => { + self.check_value_support(features, offset)?; let ty = match ty { crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty), crate::ComponentValType::Type(index) => { @@ -1348,6 +1372,7 @@ impl ComponentState { pub fn export_to_entity_type( &mut self, export: &crate::ComponentExport, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result { @@ -1359,6 +1384,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { + self.check_value_support(features, offset)?; ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { @@ -1378,7 +1404,7 @@ impl ComponentState { }; let ascribed = match &export.ty { - Some(ty) => self.check_type_ref(ty, types, offset)?, + Some(ty) => self.check_type_ref(ty, features, types, offset)?, None => return Ok(actual), }; @@ -1466,17 +1492,17 @@ impl ComponentState { } crate::ComponentTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, types, offset)?; - current.add_export(name, ty, types, offset, true)?; + let ty = current.check_type_ref(&ty, features, types, offset)?; + current.add_export(name, ty, features, types, offset, true)?; } crate::ComponentTypeDeclaration::Import(import) => { components .last_mut() .unwrap() - .add_import(import, types, offset)?; + .add_import(import, features, types, offset)?; } crate::ComponentTypeDeclaration::Alias(alias) => { - Self::add_alias(components, alias, types, offset)?; + Self::add_alias(components, alias, features, types, offset)?; } }; } @@ -1503,11 +1529,11 @@ impl ComponentState { } crate::InstanceTypeDeclaration::Export { name, ty } => { let current = components.last_mut().unwrap(); - let ty = current.check_type_ref(&ty, types, offset)?; - current.add_export(name, ty, types, offset, true)?; + let ty = current.check_type_ref(&ty, features, types, offset)?; + current.add_export(name, ty, features, types, offset, true)?; } crate::InstanceTypeDeclaration::Alias(alias) => { - Self::add_alias(components, alias, types, offset)?; + Self::add_alias(components, alias, features, types, offset)?; } }; } @@ -1690,6 +1716,7 @@ impl ComponentState { &mut self, component_index: u32, component_args: Vec, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result { @@ -1712,6 +1739,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(component_arg.index, offset)?) } ComponentExternalKind::Value => { + self.check_value_support(features, offset)?; ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?) } ComponentExternalKind::Type => { @@ -1957,6 +1985,7 @@ impl ComponentState { fn instantiate_exports( &mut self, exports: Vec, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result { @@ -2003,6 +2032,7 @@ impl ComponentState { ComponentEntityType::Func(self.function_at(export.index, offset)?) } ComponentExternalKind::Value => { + self.check_value_support(features, offset)?; ComponentEntityType::Value(*self.value_at(export.index, offset)?) } ComponentExternalKind::Type => { @@ -2229,9 +2259,13 @@ impl ComponentState { instance_index: u32, kind: ComponentExternalKind, name: &str, + features: &WasmFeatures, types: &mut TypeAlloc, offset: usize, ) -> Result<()> { + if let ComponentExternalKind::Value = kind { + self.check_value_support(features, offset)?; + } let mut ty = match types[self.instance_at(instance_index, offset)?] .unwrap_component_instance() .exports @@ -2266,7 +2300,7 @@ impl ComponentState { ); } - self.add_entity(&mut ty, None, types, offset)?; + self.add_entity(&mut ty, None, features, types, offset)?; Ok(()) } @@ -2869,6 +2903,16 @@ impl ComponentState { Ok(ty) } + + fn check_value_support(&self, features: &WasmFeatures, offset: usize) -> Result<()> { + if !features.component_model_values { + bail!( + offset, + "support for component model `value`s is not enabled" + ); + } + Ok(()) + } } impl KebabNameContext { diff --git a/fuzz/fuzz_targets/validate.rs b/fuzz/fuzz_targets/validate.rs index 02a6357e3a..1792088d19 100644 --- a/fuzz/fuzz_targets/validate.rs +++ b/fuzz/fuzz_targets/validate.rs @@ -39,6 +39,7 @@ fuzz_target!(|data: &[u8]| { memory_control: (byte3 & 0b0000_0001) != 0, function_references: (byte3 & 0b0000_0010) != 0, gc: (byte3 & 0b0000_0100) != 0, + component_model_values: (byte3 & 0b0000_1000) != 0, }); let use_maybe_invalid = byte3 & 0b0000_1000 != 0; diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index 316834e096..999f8da51d 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -106,6 +106,7 @@ fn parse_features(arg: &str) -> Result { ("multi-value", |f| &mut f.multi_value), ("tail-call", |f| &mut f.tail_call), ("component-model", |f| &mut f.component_model), + ("component-model-values", |f| &mut f.component_model_values), ("multi-memory", |f| &mut f.multi_memory), ("exception-handling", |f| &mut f.exceptions), ("memory64", |f| &mut f.memory64), diff --git a/tests/local/missing-features/component-model/value-not-enabled.wast b/tests/local/missing-features/component-model/value-not-enabled.wast new file mode 100644 index 0000000000..16b340a010 --- /dev/null +++ b/tests/local/missing-features/component-model/value-not-enabled.wast @@ -0,0 +1,41 @@ +(assert_invalid + (component + (import "f" (func $f)) + (start $f) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (import "f" (value string)) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (export "f" (value 0)) + ) + "support for component model `value`s is not enabled") + +(assert_invalid + (component + (alias export 0 "f" (value)) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (import "f1" (func)) + (export "f" (func 0) (value string)) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (component) + (instance (instantiate 0 (with "" (value 0)))) + ) + "support for component model `value`s is not enabled") +(assert_invalid + (component + (instance (export "i" (value 0))) + ) + "support for component model `value`s is not enabled") diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 8c056f5ed6..89d3bf9394 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -554,6 +554,7 @@ impl TestState { function_references: true, memory_control: true, gc: true, + component_model_values: true, }; for part in test.iter().filter_map(|t| t.to_str()) { match part { @@ -569,6 +570,7 @@ impl TestState { features.bulk_memory = false; features.function_references = false; features.gc = false; + features.component_model_values = false; } "floats-disabled.wast" => features.floats = false, "threads" => {