diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index 50cf0214b4..36dd99b9e3 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -252,10 +252,12 @@ impl ModuleTranslation<'_> { }; let info = &mut info[memory]; let data_len = u64::from(init.data.end - init.data.start); - info.data_size += data_len; - info.min_addr = info.min_addr.min(init.offset); - info.max_addr = info.max_addr.max(init.offset + data_len); - info.segments.push((idx, init.clone())); + if data_len > 0 { + info.data_size += data_len; + info.min_addr = info.min_addr.min(init.offset); + info.max_addr = info.max_addr.max(init.offset + data_len); + info.segments.push((idx, init.clone())); + } idx += 1; true }, diff --git a/tests/all/module.rs b/tests/all/module.rs index 76925462e0..285f959b72 100644 --- a/tests/all/module.rs +++ b/tests/all/module.rs @@ -110,3 +110,61 @@ fn serialize_deterministic() { assert_deterministic("(module (data \"\") (data \"\"))"); assert_deterministic("(module (elem) (elem))"); } + +// This test asserts that the optimization to transform separate data segments +// into an initialization image doesn't unnecessarily create a massive module by +// accident with a very large initialization image in it. +#[test] +fn serialize_not_overly_massive() -> Result<()> { + let mut config = Config::new(); + config.memory_guaranteed_dense_image_size(1 << 20); + let engine = Engine::new(&config)?; + + let assert_smaller_than_1mb = |module: &str| -> Result<()> { + println!("{}", module); + let bytes = Module::new(&engine, module)?.serialize()?; + assert!(bytes.len() < (1 << 20)); + Ok(()) + }; + + // Tons of space between data segments should use sparse initialization, + // along with various permutations of empty and nonempty segments. + assert_smaller_than_1mb( + r#"(module + (memory 20000) + (data (i32.const 0) "a") + (data (i32.const 0x200000) "b") + )"#, + )?; + assert_smaller_than_1mb( + r#"(module + (memory 20000) + (data (i32.const 0) "a") + (data (i32.const 0x200000) "") + )"#, + )?; + assert_smaller_than_1mb( + r#"(module + (memory 20000) + (data (i32.const 0) "") + (data (i32.const 0x200000) "b") + )"#, + )?; + assert_smaller_than_1mb( + r#"(module + (memory 20000) + (data (i32.const 0) "") + (data (i32.const 0x200000) "") + )"#, + )?; + + // lone data segment + assert_smaller_than_1mb( + r#"(module + (memory 20000) + (data (i32.const 0x200000) "b") + )"#, + )?; + + Ok(()) +}