diff --git a/crates/extension/src/wasm_host.rs b/crates/extension/src/wasm_host.rs index e4c97d2213244c386ef9ee60028ed76ea65e922f..51b306f1ff3c3b13752f44bdd550670e65581970 100644 --- a/crates/extension/src/wasm_host.rs +++ b/crates/extension/src/wasm_host.rs @@ -198,13 +198,15 @@ pub fn parse_wasm_extension_version( extension_id: &str, wasm_bytes: &[u8], ) -> Result { + let mut version = None; + for part in wasmparser::Parser::new(0).parse_all(wasm_bytes) { - if let wasmparser::Payload::CustomSection(s) = part? { + if let wasmparser::Payload::CustomSection(s) = + part.context("error parsing wasm extension")? + { if s.name() == "zed:api-version" { - let version = parse_wasm_extension_version_custom_section(s.data()); - if let Some(version) = version { - return Ok(version); - } else { + version = parse_wasm_extension_version_custom_section(s.data()); + if version.is_none() { bail!( "extension {} has invalid zed:api-version section: {:?}", extension_id, @@ -214,7 +216,13 @@ pub fn parse_wasm_extension_version( } } } - bail!("extension {} has no zed:api-version section", extension_id) + + // The reason we wait until we're done parsing all of the Wasm bytes to return the version + // is to work around a panic that can happen inside of Wasmtime when the bytes are invalid. + // + // By parsing the entirety of the Wasm bytes before we return, we're able to detect this problem + // earlier as an `Err` rather than as a panic. + version.ok_or_else(|| anyhow!("extension {} has no zed:api-version section", extension_id)) } fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option {