Fix an issue where massive memory images are created (#4112)
This commit fixes an issue introduced in #4046 where the checks for ensuring that the memory initialization image for a module was constrained in its size failed to trigger and a very small module could produce an arbitrarily large memory image. The bug in question was that if a module only had empty data segments at arbitrarily small and large addresses then the loop which checks whether or not the image is allowed was skipped entirely since it was seen that the memory had no data size. The fix here is to skip segments that are empty to ensure that if the validation loop is skipped then no data segments will be processed to create the image (and the module won't end up having an image in the end).
This commit is contained in:
@@ -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
|
||||
},
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user