Skip to content

Commit 83909b0

Browse files
authored
Verify alignment of returned component-model strings (#12897)
* Verify alignment of returned component-model strings The lifting code erroneously forgot to check for this. There's no actual consequence to this in Wasmtime per-se, but it's required in the component model spec to trap, so a trap is added here. * Fix tests * Optimize alignment check * Fix build
1 parent 0afe5fc commit 83909b0

File tree

4 files changed

+40
-6
lines changed

4 files changed

+40
-6
lines changed

crates/environ/src/component/info.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,15 @@ impl FixedEncoding {
660660
FixedEncoding::Latin1 => 1,
661661
}
662662
}
663+
664+
/// Returns the alignment of strings using this encoding.
665+
pub fn align(&self) -> u8 {
666+
match self {
667+
FixedEncoding::Utf8 => 1,
668+
FixedEncoding::Utf16 => 2,
669+
FixedEncoding::Latin1 => 2,
670+
}
671+
}
663672
}
664673

665674
/// Description of a new resource declared in a `GlobalInitializer::Resource`

crates/environ/src/fact/trampoline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,7 @@ impl<'a, 'b> Compiler<'a, 'b> {
18171817
let dst_mem = self.malloc(
18181818
dst_opts,
18191819
MallocSize::Local(dst_byte_len.idx),
1820-
dst_enc.width().into(),
1820+
dst_enc.align().into(),
18211821
);
18221822
WasmString {
18231823
ptr: dst_mem.addr,

crates/wasmtime/src/runtime/component/func/typed.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,17 +1680,21 @@ pub struct WasmStr {
16801680

16811681
impl WasmStr {
16821682
pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1683-
let byte_len = match cx.options().string_encoding {
1684-
StringEncoding::Utf8 => Some(len),
1685-
StringEncoding::Utf16 => len.checked_mul(2),
1683+
let (byte_len, align) = match cx.options().string_encoding {
1684+
StringEncoding::Utf8 => (Some(len), 1_usize),
1685+
StringEncoding::Utf16 => (len.checked_mul(2), 2),
16861686
StringEncoding::CompactUtf16 => {
16871687
if len & UTF16_TAG == 0 {
1688-
Some(len)
1688+
(Some(len), 2)
16891689
} else {
1690-
(len ^ UTF16_TAG).checked_mul(2)
1690+
((len ^ UTF16_TAG).checked_mul(2), 2)
16911691
}
16921692
}
16931693
};
1694+
debug_assert!(align.is_power_of_two());
1695+
if ptr & (align - 1) != 0 {
1696+
bail!("string pointer not aligned to {align}");
1697+
}
16941698
match byte_len.and_then(|len| ptr.checked_add(len)) {
16951699
Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?,
16961700
_ => bail!("string pointer/length out of bounds of memory"),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
;; Returning an unaligned utf16 string is invalid
2+
(component definition $A
3+
(core module $m
4+
(memory (export "m") 1)
5+
(func (export "f") (result i32)
6+
(i32.store (i32.const 4) (i32.const 1))
7+
(i32.store (i32.const 8) (i32.const 0))
8+
i32.const 4
9+
)
10+
)
11+
(core instance $m (instantiate $m))
12+
(func (export "f1") (result string)
13+
(canon lift (core func $m "f") (memory $m "m") string-encoding=utf16))
14+
(func (export "f2") (result string)
15+
(canon lift (core func $m "f") (memory $m "m") string-encoding=latin1+utf16))
16+
17+
)
18+
(component instance $A $A)
19+
(assert_trap (invoke "f1") "string pointer not aligned to 2")
20+
(component instance $A $A)
21+
(assert_trap (invoke "f2") "string pointer not aligned to 2")

0 commit comments

Comments
 (0)