Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/environ/src/fact/trampoline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2332,6 +2332,7 @@ impl<'a, 'b> Compiler<'a, 'b> {
self.instruction(Call(dst_mem_opts.realloc.unwrap().as_u32()));
self.instruction(LocalSet(dst.ptr.idx));
self.verify_aligned(dst_opts.data_model.unwrap_memory(), dst.ptr.idx, 2);
self.validate_string_inbounds(&dst, dst_byte_len.idx);

// Call the host utf16 transcoding function. This will inflate the
// prior latin1 bytes and then encode the rest of the source string
Expand Down
72 changes: 72 additions & 0 deletions tests/misc_testsuite/component-model/strings.wast
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,75 @@
(export "f" (func $c2 "f"))
)
(assert_trap (invoke "f") "unaligned pointer")

;; utf8 -> latin1+utf16
;; - first realloc fails to hold latin1
;; - second realloc is out of bounds
(component
(component $c
(core module $m
(global $cnt (mut i32) (i32.const 0))
(func (export "") (param i32 i32)
unreachable
)
(func (export "realloc") (param $old_ptr i32) (param $old_size i32)
(param $align i32) (param $new_size i32) (result i32)
(if (i32.ne (local.get $align) (i32.const 2)) (then unreachable))
(global.set $cnt (i32.add (global.get $cnt) (i32.const 1)))

;; first allocation is aligned
(if (i32.eq (global.get $cnt) (i32.const 1))
(then
(if (i32.ne (local.get $old_ptr) (i32.const 0)) (then unreachable))
(if (i32.ne (local.get $old_size) (i32.const 0)) (then unreachable))
(if (i32.ne (local.get $new_size) (i32.const 5)) (then unreachable))
(return (i32.const 2)))
)
;; second allocation is out of bounds
(if (i32.eq (global.get $cnt) (i32.const 2))
(then
(if (i32.ne (local.get $old_ptr) (i32.const 2)) (then unreachable))
(if (i32.ne (local.get $old_size) (i32.const 5)) (then unreachable))
(if (i32.ne (local.get $new_size) (i32.const 10)) (then unreachable))
(return (i32.const -2)))
)

unreachable
)
(memory (export "memory") 1)
)
(core instance $m (instantiate $m))
(func (export "a") (param "a" string)
(canon lift
(core func $m "")
(realloc (func $m "realloc"))
(memory $m "memory")
string-encoding=latin1+utf16)
)
)

(component $c2
(import "a" (func $f (param "a" string)))
(core module $libc
(memory (export "memory") 1)
;; "Ë┛" in UTF-8 is "\xc3\xab\xe2\x8c\x9b", 5 bytes.
;; * First, a 5-byte allocation is made to see if it fits in latin 1.
;; * This fails since "┛" does not fit in latin1. The second allocation
;; is then out of bounds and should trap
(data (memory 0) (i32.const 0) "Ë┛")
)
(core instance $libc (instantiate $libc))
(core func $f (canon lower (func $f) (memory $libc "memory")))
(core module $m
(import "" "" (func $f (param i32 i32)))
(func (export "f") (call $f (i32.const 0) (i32.const 5)))
)
(core instance $m (instantiate $m (with "" (instance (export "" (func $f))))))
(func (export "f") (canon lift (core func $m "f")))
)

(instance $c (instantiate $c))
(instance $c2 (instantiate $c2 (with "a" (func $c "a"))))
(export "f" (func $c2 "f"))
)
(assert_trap (invoke "f") "string content out-of-bounds")
Loading