napi: report the real byteOffset from napi_get_typedarray_info/get_dataview_info - #31524
napi: report the real byteOffset from napi_get_typedarray_info/get_dataview_info#31524alii wants to merge 1 commit into
Conversation
|
@robobun adopt |
|
Superseded by work that landed on main while this was in review: real |
|
Actionable comments posted: 0 |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
💤 Files with no reviewable changes (1)
WalkthroughThis PR moves the implementation of ChangesN-API typed array byte_offset correction
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Found 1 issue this PR may fix:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
LGTM — straightforward fix replacing the hardcoded byte_offset = 0 with JSC's JSObjectGetTypedArrayByteOffset, mirroring the adjacent JSObjectGetTypedArrayBuffer call pattern, with a Node-comparison regression test.
Extended reasoning...
Overview
This PR fixes napi_get_typedarray_info and napi_get_dataview_info in both the Zig (src/runtime/napi/napi.zig) and Rust (src/runtime/napi/napi_body.rs) implementations. Previously these functions hardcoded byte_offset = 0, breaking the N-API invariant that arraybuffer_base + byte_offset == data for views created at a non-zero offset. The fix swaps the hardcoded 0 for a call to JSC's existing JSObjectGetTypedArrayByteOffset C API. A regression test in test/napi/napi-app/standalone_tests.cpp + test/napi/napi.test.ts exercises offsets 0/4/8 for both Uint8Array and DataView, asserting the reconstructed pointer matches and comparing output against Node via checkSameOutput.
Security risks
None. The change reads a metadata field (byte offset) from an already-validated JS typed-array/DataView object via an existing JSC C API. No new untrusted input parsing, no allocation, no pointer arithmetic beyond what callers already perform with the returned values. If anything, this reduces risk: addons that compute base + byte_offset will now read the correct region instead of the wrong one.
Level of scrutiny
Low-to-medium. The core change is ~4 lines per function across two mirrored implementations, replacing a literal 0 with an FFI call that uses the identical calling convention (env.to_js(), asObjectRef(), null exception ref) as the JSObjectGetTypedArrayBuffer call two lines above it in each function. The Zig extern was already declared in javascript_core_c_api.zig:127; the Rust side adds the matching extern declaration alongside the existing JSObjectGetTypedArrayBuffer declaration. The null-pointer guard in Rust is preserved (and made explicit before the FFI call); Zig's optional unwrap already handles it.
Other factors
- The regression test uses
checkSameOutput, which runs the same N-API test under both Node and Bun and asserts identical stdout — so the test itself validates Node-compat, not just internal consistency. - No CODEOWNERS entry covers
src/runtime/napi/. - No prior reviewer comments to address.
- The bug-hunting system found no issues.
- The PR description correctly notes
data/length/arraybufferoutputs are unchanged, so existing addons that readdatadirectly are unaffected; only addons reconstructing viabase + offsetsee the (correct) behavior change.
20f4a3a to
cd23c03
Compare
Jarred-Sumner
left a comment
There was a problem hiding this comment.
I suggest moving this one to .cpp. It'll be simpler.
cd23c03 to
5d65c5c
Compare
5d65c5c to
868e5dc
Compare
868e5dc to
db60e21
Compare
db60e21 to
c798db3
Compare
8932cf2 to
f5e3da0
Compare
|
@robobun — two things from Jarred's review:
Keep the behavior and the N-API regression test unchanged: |
b954ed0 to
8655217
Compare
8655217 to
f536291
Compare
f536291 to
fea749b
Compare
|
@robobun Get this mergable |
|
@alii I went to rebase this (it's 1377 commits behind and conflicts in 4 files) and found it's been superseded on main. Everything this PR fixes has already landed, in the Rust impl, with Node-compared tests:
So the functional delta left in this PR is zero, and merging it would only move working Rust into ~400 lines of C++. I'd close this rather than rebase it. The one tiny thing not on main is rejecting a mismatched view subtype when Happy to do the rebase instead if you still want the C++ move for its own sake, but I don't think it's worth it. |
|
Want to just close this then if it's already fixed? |
napi_get_typedarray_infoandnapi_get_dataview_infoalways wrotebyte_offset = 0, so a native addon doing the canonical zero-copy reconstructionarraybuffer.Data() + byte_offsetread the wrong region for any view created at a non-zero offset (e.g.new Uint8Array(buf, 4)→ the addon read byte 0 instead of byte 4). The returned{arraybuffer, byte_offset, data}triple was self-inconsistent:data= base+offset, butbyte_offset= 0 andarraybuffer= base, sobase + byte_offset != data.dataalready has the offset folded in, so report the view's realbyteOffset(via JSC's existingJSObjectGetTypedArrayByteOffset) instead of 0 — makingbase + byte_offset == data, matching Node. Covers both typedarray and dataview, null-guarded; zero-offset views still report 0;length/data/arraybufferunchanged.Adds an N-API regression test (offset views at 0/4/8 for
Uint8Array+DataView, assertingbyte_offsetand thebase + byte_offset == datareconstruction match Node). Not a port regression — 1.3.14 also returns 0.