diff --git a/test/values/strings.wast b/test/values/strings.wast index 0628effc..e838ccdd 100644 --- a/test/values/strings.wast +++ b/test/values/strings.wast @@ -24,6 +24,37 @@ (assert_return (invoke "f1") (str.const "a")) (assert_return (invoke "f2") (str.const "☃☺️öツ")) +;; empty string with ptr=0, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 0)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; empty string with non-zero in-bounds ptr, len=0 +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 100)) + (i32.store (i32.const 4) (i32.const 0)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "")) + +;; out-of-bounds pointer traps even with len=0 (component (core module $M (memory (export "mem") 1) @@ -37,3 +68,69 @@ (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) ) (assert_trap (invoke "f") "string pointer/length out of bounds of memory") + +;; invalid UTF-8: 0xFF is never valid +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xff)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "invalid utf-8") + +;; truncated multibyte UTF-8: leading byte 0xC3 expects a continuation byte +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 8)) + (i32.store (i32.const 4) (i32.const 1)) + (i32.store8 (i32.const 8) (i32.const 0xc3)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "incomplete utf-8 byte sequence") + +;; string at end of memory page boundary +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + ;; place "ok" at the very end of the first page (65536 - 2 = 65534) + (i32.store (i32.const 0) (i32.const 65534)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65534) (i32.const 111)) ;; 'o' + (i32.store8 (i32.const 65535) (i32.const 107)) ;; 'k' + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_return (invoke "f") (str.const "ok")) + +;; string one byte past end of memory traps +(component + (core module $M + (memory (export "mem") 1) + (func (export "f") (result i32) + (i32.store (i32.const 0) (i32.const 65535)) + (i32.store (i32.const 4) (i32.const 2)) + (i32.store8 (i32.const 65535) (i32.const 111)) + (i32.const 0) + ) + ) + (core instance $m (instantiate $M)) + (func (export "f") (result string) (canon lift (core func $m "f") (memory $m "mem"))) +) +(assert_trap (invoke "f") "string pointer/length out of bounds of memory")