Skip to content

fix(ext/node): make zlib writeSync _writeState argument optional (#35185)#35207

Open
tsushanth wants to merge 4 commits into
denoland:mainfrom
tsushanth:fix-zlib-writeSync-optional-state
Open

fix(ext/node): make zlib writeSync _writeState argument optional (#35185)#35207
tsushanth wants to merge 4 commits into
denoland:mainfrom
tsushanth:fix-zlib-writeSync-optional-state

Conversation

@tsushanth

Copy link
Copy Markdown

Closes #35185. Compat regression introduced by #35043.

#35043 moved the zlib write-result buffer (_writeState) from a pointer cached at handle init to a per-call argument on _handle.writeSync(...). The Rust op required it (#[buffer] write_result: &mut [u32]), so callers that bind directly to _handle.writeSync and never knew about per-call state — notably pngjs's sync-inflate.js, which is what png-to-ico (and the reporter's fount) pull in — now hit TypeError: expected typed ArrayBufferView when v8 sees undefined for the 8th slot. The high-level zlib.inflateSync / async PNG.parse() paths are unaffected because Deno's own zlib.js always passes the buffer.

This makes the per-call result buffer optional in the Inflate op signature:

  • #[buffer] write_result: Option<&mut [u32]>
  • the avail_out/avail_in write-back becomes if let Some(write_result) = write_result

When a caller does pass a state buffer (which Deno's polyfill, and any post-#35043 external code, does), the behavior is byte-for-byte identical — the security fix for the detached-buffer case is preserved because the per-call argument is still validated as a typed array. When a caller doesn't, the op just runs the inflate/deflate step without surfacing the post-write avail counts; the legacy contract for pngjs (which then reads its own bookkeeping) is restored.

Scope: the BrotliEncoder / BrotliDecoder / ZstdCompress / ZstdDecompress ops have the same write_result: &mut [u32] parameter, but I deliberately left them as-is. They postdate the pngjs era and we don't have an external caller report against them; the Inflate path is the one with a confirmed in-the-wild compat regression. Happy to widen the fix in a follow-up if the team prefers symmetry.

Tests

Added "zlib writeSync accepts the pre-#35043 seven-argument signature" in tests/unit_node/zlib_test.ts, mirroring the reporter's minimal repro: a zlib.createInflate() whose _handle.writeSync is invoked with seven arguments must not throw. Pre-fix this throws TypeError: expected typed ArrayBufferView; post-fix it returns successfully.

The detached-_writeState tests added by #35043 (writeSync does not write through a detached _writeState, writeSync populates _writeState per call) continue to pass since they exercise the eight-argument path that this PR doesn't change.

@deno-cla-assistant

Copy link
Copy Markdown

Deno Individual Contributor License Agreement

The following contributors need to sign the CLA before this PR can be merged:

Click here to review and sign the CLA | Re-run CLA check


This is an automated message from CLA Assistant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

node:zlib Inflate._handle.writeSync() throws expected typed ArrayBufferView in 2.8.3 (worked in 2.8.2)

1 participant