wasm asm: read_string handles \" \\ \n \t escapes — bend payload works
The WAT $read_string function scanned bytes until the first " and copied
raw, with NO escape handling. So a source string like
"(\"00\" \"01\")" got chopped at the first \" — the asm tier read only
"(\\" before terminating, producing a mangled payload that the worker
couldn't parse. The bend-gpu demo's payload built via string-append of
escaped-quote strings came out as "(cuda-shake-fanout (\ \ \) 32)" in
the asm tier, sent garbage to bend, and got nothing useful back.
Two-pass fix to match Python/C tier behavior:
1. Scan-and-count pass: walks source-ptr to the closing ", but
when it sees \ it skips the next byte so embedded \" doesn't
terminate the string. Counts decoded output bytes (each \X
contributes one byte, not two).
2. Allocate + copy-and-decode pass: walks the same range, converts
\n → 0x0A, \t → 0x09, and any other \X (including \" and \\)
→ X. Matches the lenient fallback the desktop tiers use.
Verified via cross-tier parity probe — 255/255 still passing.
Demo payload now constructs as
"(cuda-shake-fanout (\"00\" \"01\" \"deadbeef\") 32)" (45 bytes,
identical to Python/C reads) and the asm playground returns
(ok (HEX0 HEX1 HEX2)) from the live 3090-ai bend worker.
This commit is contained in:
parent
0cf66cc3dd
commit
d672ab077e
4 changed files with 43 additions and 13 deletions
|
|
@ -1781,35 +1781,65 @@
|
|||
(i32.const 1))
|
||||
|
||||
;; Read a string literal (we've already consumed the opening ").
|
||||
;; Read a "..." string literal. Handles escape sequences inside the
|
||||
;; literal: \" → " (so a string can contain a literal quote), \\ → \,
|
||||
;; \n → newline, \t → tab. Any other \X falls back to literal X
|
||||
;; (same fallback the Python/C tiers use). Two-pass: first pass
|
||||
;; counts output bytes & locates closing quote, second copies the
|
||||
;; payload performing escape conversion.
|
||||
(func $read_string (result i32)
|
||||
(local $start i32)
|
||||
(local $len i32)
|
||||
(local $end i32)
|
||||
(local $bytes i32)
|
||||
(local $s i32)
|
||||
(local $i i32)
|
||||
(local $src i32)
|
||||
(local $dst i32)
|
||||
(local $ch i32)
|
||||
(local $next i32)
|
||||
(local.set $start (global.get $source_ptr))
|
||||
(local.set $bytes (i32.const 0))
|
||||
;; First pass: scan to closing ", counting decoded output bytes.
|
||||
(block $done
|
||||
(loop $loop
|
||||
(br_if $done (i32.ge_u (global.get $source_ptr) (global.get $source_end)))
|
||||
(br_if $done
|
||||
(i32.eq (i32.load8_u (global.get $source_ptr)) (i32.const 34)))
|
||||
(local.set $ch (i32.load8_u (global.get $source_ptr)))
|
||||
(br_if $done (i32.eq (local.get $ch) (i32.const 34))) ;; closing "
|
||||
(if (i32.eq (local.get $ch) (i32.const 92)) ;; \
|
||||
(then
|
||||
(global.set $source_ptr (i32.add (global.get $source_ptr) (i32.const 1)))
|
||||
(br_if $done (i32.ge_u (global.get $source_ptr) (global.get $source_end)))))
|
||||
(local.set $bytes (i32.add (local.get $bytes) (i32.const 1)))
|
||||
(global.set $source_ptr (i32.add (global.get $source_ptr) (i32.const 1)))
|
||||
(br $loop)))
|
||||
(local.set $len (i32.sub (global.get $source_ptr) (local.get $start)))
|
||||
(local.set $end (global.get $source_ptr))
|
||||
;; consume closing "
|
||||
(if (i32.lt_u (global.get $source_ptr) (global.get $source_end))
|
||||
(then (global.set $source_ptr (i32.add (global.get $source_ptr) (i32.const 1)))))
|
||||
;; Allocate a string object (same layout as symbol but tag=5).
|
||||
(local.set $s (call $alloc (i32.add (i32.const 8) (local.get $len))))
|
||||
(local.set $s (call $alloc (i32.add (i32.const 8) (local.get $bytes))))
|
||||
(i32.store (local.get $s) (i32.const 5))
|
||||
(i32.store offset=4 (local.get $s) (local.get $len))
|
||||
(local.set $i (i32.const 0))
|
||||
(i32.store offset=4 (local.get $s) (local.get $bytes))
|
||||
;; Second pass: copy with escape conversion.
|
||||
(local.set $src (local.get $start))
|
||||
(local.set $dst (i32.add (local.get $s) (i32.const 8)))
|
||||
(block $cdone
|
||||
(loop $cloop
|
||||
(br_if $cdone (i32.ge_u (local.get $i) (local.get $len)))
|
||||
(i32.store8
|
||||
(i32.add (i32.add (local.get $s) (i32.const 8)) (local.get $i))
|
||||
(i32.load8_u (i32.add (local.get $start) (local.get $i))))
|
||||
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
||||
(br_if $cdone (i32.ge_u (local.get $src) (local.get $end)))
|
||||
(local.set $ch (i32.load8_u (local.get $src)))
|
||||
(if (i32.eq (local.get $ch) (i32.const 92)) ;; \
|
||||
(then
|
||||
(local.set $src (i32.add (local.get $src) (i32.const 1)))
|
||||
(if (i32.lt_u (local.get $src) (local.get $end))
|
||||
(then
|
||||
(local.set $next (i32.load8_u (local.get $src)))
|
||||
(local.set $ch
|
||||
(if (result i32) (i32.eq (local.get $next) (i32.const 110)) (then (i32.const 10)) ;; \n
|
||||
(else
|
||||
(if (result i32) (i32.eq (local.get $next) (i32.const 116)) (then (i32.const 9)) ;; \t
|
||||
(else (local.get $next)))))))))) ;; \" → ", \\ → \, \X → X
|
||||
(i32.store8 (local.get $dst) (local.get $ch))
|
||||
(local.set $src (i32.add (local.get $src) (i32.const 1)))
|
||||
(local.set $dst (i32.add (local.get $dst) (i32.const 1)))
|
||||
(br $cloop)))
|
||||
(local.get $s))
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue