Skip to content

Commit 958860e

Browse files
authored
Fix overlap assertions in string transcoding (#12893)
Fixes an off-by-one assertion which is possible to happen when linear memories are directly adjacent to each other. While an esoteric situation, it's technically possible as the added test shows. Closes #12678
1 parent f10f708 commit 958860e

2 files changed

Lines changed: 73 additions & 3 deletions

File tree

crates/wasmtime/src/runtime/vm/component/libcalls.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ fn assert_no_overlap<T, U>(a: &[T], b: &[U]) {
171171
let b_end = b_start + (b.len() * core::mem::size_of::<U>());
172172

173173
if a_start < b_start {
174-
assert!(a_end < b_start);
174+
assert!(a_end <= b_start);
175175
} else {
176-
assert!(b_end < a_start);
176+
assert!(b_end <= a_start);
177177
}
178178
}
179179

tests/all/component_model/strings.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::REALLOC_AND_FREE;
44
use wasmtime::Result;
55
use wasmtime::component::{Component, Linker};
6-
use wasmtime::{Engine, Store, StoreContextMut, Trap};
6+
use wasmtime::{Config, Engine, PoolingAllocationConfig, Store, StoreContextMut, Trap};
77

88
const UTF16_TAG: u32 = 1 << 31;
99

@@ -576,3 +576,73 @@ fn test_raw_when_encoded(
576576
Err(e) => Ok(Some(e)),
577577
}
578578
}
579+
580+
#[test]
581+
fn pass_string_on_component_boundary() -> Result<()> {
582+
// Configure an engine such that linear memories are allocated right next
583+
// to each other and are 1 wasm page large. This'll ensure that the string
584+
// at the beginning of the second memory is at the end of the first memory.
585+
let mut pooling_config = PoolingAllocationConfig::new();
586+
pooling_config.total_component_instances(3);
587+
pooling_config.total_memories(2);
588+
pooling_config.total_tables(0);
589+
pooling_config.total_stacks(0);
590+
pooling_config.max_memory_size(65536);
591+
let mut config = Config::new();
592+
config.memory_guard_size(0);
593+
config.memory_reservation(65536);
594+
config.allocation_strategy(pooling_config);
595+
let engine = Engine::new(&config)?;
596+
597+
let component = r#"
598+
(component
599+
;; This component is instantiated first so its allocation function returns a
600+
;; pointer at the end of memory which will be right up against the next
601+
;; linear memory.
602+
(component $c
603+
(core module $m
604+
(func (export "") (param i32 i32))
605+
(func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 65520)
606+
(memory (export "memory") 1)
607+
)
608+
(core instance $m (instantiate $m))
609+
(func (export "a") (param "a" string)
610+
(canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory"))
611+
)
612+
)
613+
614+
;; This component is instantiated second meaning its memory is after the
615+
;; one above, so the string is placed first thing in linear memory.
616+
(component $c2
617+
(import "a" (func $f (param "a" string)))
618+
(core module $libc
619+
(memory (export "memory") 1)
620+
(data (memory 0) (i32.const 0) "0123456789abcdef")
621+
)
622+
(core instance $libc (instantiate $libc))
623+
(core func $f (canon lower (func $f) (memory $libc "memory")))
624+
(core module $m
625+
(import "" "" (func $f (param i32 i32)))
626+
(func (export "f")
627+
(call $f
628+
(i32.const 0) ;; ptr
629+
(i32.const 16)) ;; len
630+
)
631+
)
632+
(core instance $m (instantiate $m (with "" (instance (export "" (func $f))))))
633+
(func (export "f") (canon lift (core func $m "f")))
634+
)
635+
636+
(instance $c (instantiate $c))
637+
(instance $c2 (instantiate $c2 (with "a" (func $c "a"))))
638+
(export "f" (func $c2 "f"))
639+
)
640+
"#;
641+
642+
let component = Component::new(&engine, &component)?;
643+
let mut store = Store::new(&engine, ());
644+
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
645+
let func = instance.get_typed_func::<(), ()>(&mut store, "f")?;
646+
func.call(&mut store, ())?;
647+
Ok(())
648+
}

0 commit comments

Comments
 (0)