Repository navigation
fix(wasm): size the query buffer from the bytes actually written; reject embedded NUL - #173
pyramation wants to merge 2 commits into
Conversation
stringToPtr sized the buffer with lengthBytesUTF8 and wrote with stringToUTF8, which disagree on unpaired surrogates (4 bytes per two units vs 3 bytes each), so the write stopped short and the tail of the query was silently dropped. An embedded NUL likewise ended the C string early. Encode once with TextEncoder (unpaired surrogates become U+FFFD, the bytes a Postgres driver sends), allocate exactly that many bytes plus the terminator, and throw on an embedded NUL. Fixes #169
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
Review complete. No issues found — approved ✅. This PR rewrites the string-to-WASM-pointer marshaling in
No reviewable defects were confirmed; all candidate issues were rejected on verification against the source. Reviewed commit: 65e440f |
…3 tests cover src/
…o's wrapper On main the v13 job runs the wrapper bundled in @libpg-query/v13@13.5.7, so the recovery test exercised the old wrapper and hung. Also bound the recovery suite with a 120 s timeout so a regression fails instead of hanging.
Summary
Fixes #169. Before this change, the wrapper could parse less than the query it was given and report no error.
stringToPtrsized the input buffer with Emscripten'slengthBytesUTF8and then wrote it withstringToUTF8. The two count unpaired surrogates differently:lengthBytesUTF8counts 4 bytes for every two code units.stringToUTF8writes 3 bytes for each code unit.So the buffer came out too small, the write stopped early, and the end of the query was dropped. Depending on where the cut fell, the second statement disappeared or the parser threw a bogus syntax error. An embedded
U+0000ended the C string early in the same way.The change is made in
templates/index.tsandtemplates/full/index.ts, then copied intoversions/*/src/index.ts.HEAPU8was already inEXPORTED_RUNTIME_METHODS; it is now also declared in the full-API types.Why replace unpaired surrogates instead of throwing: Node Postgres drivers encode strings with the same WHATWG UTF-8 encoder, which turns an unpaired surrogate into U+FFFD. Postgres therefore receives U+FFFD, and the parse tree now reflects exactly those bytes. UTF-16 offsets don't move, because one code unit becomes one code unit. A NUL is rejected because Postgres can't receive one in query text at all.
CI (v13): the v13 job used to extract the whole
wasm/dir of the prebuilt@libpg-query/v13@13.5.7, wrapper included, so v13 tests never ran this repo'ssrc/. It now extracts onlylibpg-query.{js,wasm}and runspnpm run build:js. That is what made v13 fail on the first push: it was testing the old wrapper.Evidence (reproduce first)
The new
test/input-encoding.test.jswas added to everyversions/*package and wired into eachtestscript.libpg-query@18.1.5(before the fix): 3 pass / 7 fail. 4, 8, 16 and 64 lone surrogates, lone low surrogates, U+FFFD read-back and NUL rejection all fail. The 1/2-surrogate and valid-pair cases pass.versions/18build with the fix: full suite 102 / 102 pass, new file 10 / 10.tsc --noEmitis clean forversions/13–17. CI builds and tests all six versions on three OSes.Not in this PR:
pnpm run copy:templatesalso rewritesversions/15|17|18/Makefile, becausetemplates/Makefile.templatehas drifted from them. It would point them back at pganalyze tags and drop the v18 memory knobs. I left the Makefiles unchanged.Link to Devin session: https://app.devin.ai/sessions/bcd8b2f791164247acb7a659b481efc2
Open in Devin Desktop: https://app.devin.ai/desktop/session/bcd8b2f791164247acb7a659b481efc2?variant=devin
Requested by: @pyramation