1;;! multi_memory = true 2 3;; Returning an unaligned utf16 string is invalid 4(component definition $A 5 (core module $m 6 (memory (export "m") 1) 7 (func (export "f") (result i32) 8 (i32.store (i32.const 4) (i32.const 1)) 9 (i32.store (i32.const 8) (i32.const 0)) 10 i32.const 4 11 ) 12 ) 13 (core instance $m (instantiate $m)) 14 (func (export "f1") (result string) 15 (canon lift (core func $m "f") (memory $m "m") string-encoding=utf16)) 16 (func (export "f2") (result string) 17 (canon lift (core func $m "f") (memory $m "m") string-encoding=latin1+utf16)) 18 19) 20(component instance $A $A) 21(assert_trap (invoke "f1") "string pointer not aligned to 2") 22(component instance $A $A) 23(assert_trap (invoke "f2") "string pointer not aligned to 2") 24 25;; utf8 -> utf16 -- when shrinking memory it must be aligned 26(component 27 (component $c 28 (core module $m 29 (func (export "") (param i32 i32) unreachable) 30 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 31 (param $align i32) (param $new_size i32) (result i32) 32 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 33 (if (result i32) (i32.eqz (local.get $old_ptr)) 34 (then (i32.const 2)) ;; first allocation aligned 35 (else (i32.const 3)) ;; second allocation unaligned 36 ) 37 ) 38 (memory (export "memory") 1) 39 ) 40 (core instance $m (instantiate $m)) 41 (func (export "a") (param "a" string) 42 (canon lift 43 (core func $m "") 44 (realloc (func $m "realloc")) 45 (memory $m "memory") 46 string-encoding=utf16) 47 ) 48 ) 49 50 (component $c2 51 (import "a" (func $f (param "a" string))) 52 (core module $libc 53 (memory (export "memory") 1) 54 ;; "àà" is 2 UTF-16 code units (4 bytes), and 4 bytes in UTF-8 55 ;; Pessimistic alloc = 4 * 2 = 8 bytes, shrinks to 4 bytes after. 56 (data (memory 0) (i32.const 0) "àà") 57 ) 58 (core instance $libc (instantiate $libc)) 59 (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) 60 (core module $m 61 (import "" "" (func $f (param i32 i32))) 62 (func (export "f") (call $f (i32.const 0) (i32.const 4))) 63 ) 64 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 65 (func (export "f") (canon lift (core func $m "f"))) 66 ) 67 68 (instance $c (instantiate $c)) 69 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 70 (export "f" (func $c2 "f")) 71) 72 73(assert_trap (invoke "f") "unaligned pointer") 74 75;; utf16 -> latin1+utf16 -- when shrinking memory it must be aligned 76(component 77 (component $c 78 (core module $m 79 (func (export "") (param i32 i32)) 80 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 81 (param $align i32) (param $new_size i32) (result i32) 82 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 83 (if (result i32) (i32.eqz (local.get $old_ptr)) 84 (then (i32.const 2)) ;; first allocation aligned 85 (else (i32.const 3)) ;; second allocation unaligned 86 ) 87 ) 88 (memory (export "memory") 1) 89 ) 90 (core instance $m (instantiate $m)) 91 (func (export "a") (param "a" string) 92 (canon lift 93 (core func $m "") 94 (realloc (func $m "realloc")) 95 (memory $m "memory") 96 string-encoding=latin1+utf16) 97 ) 98 ) 99 100 (component $c2 101 (import "a" (func $f (param "a" string))) 102 (core module $libc 103 (memory (export "memory") 1) 104 ;; "AΣ" in UTF-16: 0x41 0x00 0xA3 0x03 (Σ = U+03A3, not Latin-1) 105 ;; Forces transcoding to take the UTF-16 grow path. 106 (data (memory 0) (i32.const 0) "\41\00\a3\03") 107 ) 108 (core instance $libc (instantiate $libc)) 109 (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) 110 (core module $m 111 (import "" "" (func $f (param i32 i32))) 112 (func (export "f") (call $f (i32.const 0) (i32.const 2))) 113 ) 114 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 115 (func (export "f") (canon lift (core func $m "f"))) 116 ) 117 118 (instance $c (instantiate $c)) 119 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 120 (export "f" (func $c2 "f")) 121) 122(assert_trap (invoke "f") "unaligned pointer") 123 124;; latin1+utf16 -> latin1+utf16 -- auto-downsize 125(component 126 (component $c 127 (core module $m 128 (func (export "") (param i32 i32) unreachable) 129 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 130 (param $align i32) (param $new_size i32) (result i32) 131 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 132 (if (result i32) (i32.eqz (local.get $old_ptr)) 133 (then (i32.const 2)) ;; first allocation aligned 134 (else (i32.const 3)) ;; second allocation unaligned 135 ) 136 ) 137 (memory (export "memory") 1) 138 ) 139 (core instance $m (instantiate $m)) 140 (func (export "a") (param "a" string) 141 (canon lift 142 (core func $m "") 143 (realloc (func $m "realloc")) 144 (memory $m "memory") 145 string-encoding=latin1+utf16) 146 ) 147 ) 148 149 (component $c2 150 (import "a" (func $f (param "a" string))) 151 (core module $libc 152 (memory (export "memory") 1) 153 ;; "AA" in UTF-16: 0x41 0x00 0x41 0x00 154 (data (memory 0) (i32.const 0) "\41\00\41\00") 155 ) 156 (core instance $libc (instantiate $libc)) 157 (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) 158 (core module $m 159 (import "" "" (func $f (param i32 i32))) 160 ;; the length here contains `UTF16_TAG` and it's additionally 1 code 161 ;; unit. This is a utf-16 encoded string but during transcoding it'll 162 ;; get shrunk to latin 1 163 (func (export "f") (call $f (i32.const 0) (i32.const 0x8000_0002))) 164 ) 165 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 166 (func (export "f") (canon lift (core func $m "f"))) 167 ) 168 169 (instance $c (instantiate $c)) 170 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 171 (export "f" (func $c2 "f")) 172) 173(assert_trap (invoke "f") "unaligned pointer") 174 175;; utf8 -> latin1+utf16 -- initial encode finishes but needs downsizing 176(component 177 (component $c 178 (core module $m 179 (func (export "") (param i32 i32) unreachable) 180 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 181 (param $align i32) (param $new_size i32) (result i32) 182 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 183 (if (result i32) (i32.eqz (local.get $old_ptr)) 184 (then (i32.const 2)) ;; first allocation aligned 185 (else (i32.const 3)) ;; second allocation unaligned 186 ) 187 ) 188 (memory (export "memory") 1) 189 ) 190 (core instance $m (instantiate $m)) 191 (func (export "a") (param "a" string) 192 (canon lift 193 (core func $m "") 194 (realloc (func $m "realloc")) 195 (memory $m "memory") 196 string-encoding=latin1+utf16) 197 ) 198 ) 199 200 (component $c2 201 (import "a" (func $f (param "a" string))) 202 (core module $libc 203 (memory (export "memory") 1) 204 ;; "Ë" in UTF-8 is "\xc3\xab", which is 2 bytes, but in latin1+utf16 it's 205 ;; 1 byte (0xCB). The initial allocation of 2 bytes completes the entire 206 ;; transcode but the final allocation needs to be shrunk to 1 byte. 207 (data (memory 0) (i32.const 0) "Ë") 208 ) 209 (core instance $libc (instantiate $libc)) 210 (core func $f (canon lower (func $f) (memory $libc "memory"))) 211 (core module $m 212 (import "" "" (func $f (param i32 i32))) 213 (func (export "f") (call $f (i32.const 0) (i32.const 2))) 214 ) 215 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 216 (func (export "f") (canon lift (core func $m "f"))) 217 ) 218 219 (instance $c (instantiate $c)) 220 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 221 (export "f" (func $c2 "f")) 222) 223(assert_trap (invoke "f") "unaligned pointer") 224 225;; utf8 -> latin1+utf16 226;; - first realloc fails to hold latin1 227;; - second realloc is too big 228;; - third realloc shrinks 229(component 230 (component $c 231 (core module $m 232 (global $cnt (mut i32) (i32.const 0)) 233 (func (export "") (param i32 i32) 234 unreachable 235 ) 236 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 237 (param $align i32) (param $new_size i32) (result i32) 238 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 239 (global.set $cnt (i32.add (global.get $cnt) (i32.const 1))) 240 241 ;; first allocation is aligned 242 (if (i32.eq (global.get $cnt) (i32.const 1)) 243 (then 244 (if (i32.ne (local.get $old_ptr) (i32.const 0)) (then unreachable)) 245 (if (i32.ne (local.get $old_size) (i32.const 0)) (then unreachable)) 246 (if (i32.ne (local.get $new_size) (i32.const 5)) (then unreachable)) 247 (return (i32.const 2))) 248 ) 249 ;; second allocation is aligned 250 (if (i32.eq (global.get $cnt) (i32.const 2)) 251 (then 252 (if (i32.ne (local.get $old_ptr) (i32.const 2)) (then unreachable)) 253 (if (i32.ne (local.get $old_size) (i32.const 5)) (then unreachable)) 254 (if (i32.ne (local.get $new_size) (i32.const 10)) (then unreachable)) 255 (return (i32.const 4))) 256 ) 257 ;; third allocation is unaligned 258 (if (i32.eq (global.get $cnt) (i32.const 3)) 259 (then 260 (if (i32.ne (local.get $old_ptr) (i32.const 4)) (then unreachable)) 261 (if (i32.ne (local.get $old_size) (i32.const 10)) (then unreachable)) 262 (if (i32.ne (local.get $new_size) (i32.const 4)) (then unreachable)) 263 (return (i32.const 3))) 264 ) 265 266 unreachable 267 ) 268 (memory (export "memory") 1) 269 ) 270 (core instance $m (instantiate $m)) 271 (func (export "a") (param "a" string) 272 (canon lift 273 (core func $m "") 274 (realloc (func $m "realloc")) 275 (memory $m "memory") 276 string-encoding=latin1+utf16) 277 ) 278 ) 279 280 (component $c2 281 (import "a" (func $f (param "a" string))) 282 (core module $libc 283 (memory (export "memory") 1) 284 ;; "Ë┛" in UTF-8 is "\xc3\xab\xe2\x8c\x9b", 5 bytes. 285 ;; * First, a 5-byte allocation is made to see if it fits in latin 1. 286 ;; * This fails since "┛" does not fit in latin1. The second allocation 287 ;; is over-large at 10 bytes (twice the original length). 288 ;; * The string encoded in UTF-16 is "\xcb\x00\x1b%", which is 4 bytes. 289 ;; * The 10-byte allocation is shrunk to 4 bytes, which is what this 290 ;; test is looking for (proper alignment in the 3rd realloc). 291 (data (memory 0) (i32.const 0) "Ë┛") 292 ) 293 (core instance $libc (instantiate $libc)) 294 (core func $f (canon lower (func $f) (memory $libc "memory"))) 295 (core module $m 296 (import "" "" (func $f (param i32 i32))) 297 (func (export "f") (call $f (i32.const 0) (i32.const 5))) 298 ) 299 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 300 (func (export "f") (canon lift (core func $m "f"))) 301 ) 302 303 (instance $c (instantiate $c)) 304 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 305 (export "f" (func $c2 "f")) 306) 307(assert_trap (invoke "f") "unaligned pointer") 308 309;; utf8 -> latin1+utf16 310;; - first realloc fails to hold latin1 311;; - second realloc is out of bounds 312(component 313 (component $c 314 (core module $m 315 (global $cnt (mut i32) (i32.const 0)) 316 (func (export "") (param i32 i32) 317 unreachable 318 ) 319 (func (export "realloc") (param $old_ptr i32) (param $old_size i32) 320 (param $align i32) (param $new_size i32) (result i32) 321 (if (i32.ne (local.get $align) (i32.const 2)) (then unreachable)) 322 (global.set $cnt (i32.add (global.get $cnt) (i32.const 1))) 323 324 ;; first allocation is aligned 325 (if (i32.eq (global.get $cnt) (i32.const 1)) 326 (then 327 (if (i32.ne (local.get $old_ptr) (i32.const 0)) (then unreachable)) 328 (if (i32.ne (local.get $old_size) (i32.const 0)) (then unreachable)) 329 (if (i32.ne (local.get $new_size) (i32.const 5)) (then unreachable)) 330 (return (i32.const 2))) 331 ) 332 ;; second allocation is out of bounds 333 (if (i32.eq (global.get $cnt) (i32.const 2)) 334 (then 335 (if (i32.ne (local.get $old_ptr) (i32.const 2)) (then unreachable)) 336 (if (i32.ne (local.get $old_size) (i32.const 5)) (then unreachable)) 337 (if (i32.ne (local.get $new_size) (i32.const 10)) (then unreachable)) 338 (return (i32.const -2))) 339 ) 340 341 unreachable 342 ) 343 (memory (export "memory") 1) 344 ) 345 (core instance $m (instantiate $m)) 346 (func (export "a") (param "a" string) 347 (canon lift 348 (core func $m "") 349 (realloc (func $m "realloc")) 350 (memory $m "memory") 351 string-encoding=latin1+utf16) 352 ) 353 ) 354 355 (component $c2 356 (import "a" (func $f (param "a" string))) 357 (core module $libc 358 (memory (export "memory") 1) 359 ;; "Ë┛" in UTF-8 is "\xc3\xab\xe2\x8c\x9b", 5 bytes. 360 ;; * First, a 5-byte allocation is made to see if it fits in latin 1. 361 ;; * This fails since "┛" does not fit in latin1. The second allocation 362 ;; is then out of bounds and should trap 363 (data (memory 0) (i32.const 0) "Ë┛") 364 ) 365 (core instance $libc (instantiate $libc)) 366 (core func $f (canon lower (func $f) (memory $libc "memory"))) 367 (core module $m 368 (import "" "" (func $f (param i32 i32))) 369 (func (export "f") (call $f (i32.const 0) (i32.const 5))) 370 ) 371 (core instance $m (instantiate $m (with "" (instance (export "" (func $f)))))) 372 (func (export "f") (canon lift (core func $m "f"))) 373 ) 374 375 (instance $c (instantiate $c)) 376 (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) 377 (export "f" (func $c2 "f")) 378) 379(assert_trap (invoke "f") "string content out-of-bounds") 380