Skip to content

test: property-based fuzz testing for js->zig->js roundtrip - #41

Open
nazarhussain wants to merge 22 commits into
mainfrom
nh/fuzz-testing
Open

test: property-based fuzz testing for js->zig->js roundtrip#41
nazarhussain wants to merge 22 commits into
mainfrom
nh/fuzz-testing

Conversation

@nazarhussain

Copy link
Copy Markdown
Contributor

Adds a property-based fuzz harness for zapi Number, BigInt and Uint8Array converters and (vitest + fast-check, driven through a dedicated test_fuzz_numeric.node addon). The harness immediately surfaced multiple latent bugs and an API sharp edge, all addressed in this branch.

API changes

  • Safer-by-default toI64 / toU64 / toI128: these now return error.InvalidArg on out-of-range BigInts instead of silently truncating. Callers who explicitly want low-bits semantics use the new toI64LowBits / toU64LowBits / toI128LowBits variants. NAPI's lossless flag is exposed as the lossless out-pointer on the *LowBits calls.
  • New BigInt.fromWords(sign_bit, words) — DSL surface for constructing BigInts whose magnitude exceeds u64 (e.g., i128). Closes the gap the existing BigInt.from doc comment noted but couldn't fill.
  • Doc comments on Number.toI32/U32/F64/I64 updated to accurately describe N-API conversion semantics (NaN/Inf → 0, range clamping, etc.).

nazarhussain and others added 21 commits May 28, 2026 12:56
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NAPI sets word_count to the required size even when the buffer is
smaller than needed; the previous code returned words[0..word_count],
which is UB when word_count > words.len. Clamping via @min makes the
function safe and gives callers the semantics of truncate-to-low-N-bits.
Previous toI128 panicked on three input classes: zero (result[0] on
empty slice), minInt(i128) (@intcast overflow during negation), and
out-of-range magnitudes. Reworks the function to use a pre-zeroed local
buffer and wrapping arithmetic, returning BigInt.asIntN(128, b)
semantics for out-of-domain inputs.

Documents the in-domain (exact) and out-of-domain (truncation) contract
in the doc comment, and adds an explicit comment on the magnitude == 0
guard for out-of-range negatives whose low 128 bits are all zero
(e.g. -2^128n), where asIntN(128, b) === 0n.
Thin DSL wrapper over napi_create_bigint_words. Required for
round-tripping i128 and larger values through the DSL without going
through the i64/u64 path. Accepts a sign bit and a little-endian
u64-word slice; the resulting BigInt equals
(sign == 1 ? -1 : 1) * sum(words[i] << (64 * i)).
Round-trips JS BigInt → i128 → JS BigInt via toI128 and fromWords.
Property test covers the i128 boundary plus out-of-range truncation via
BigInt.asIntN(128, ·). Oracle test adds deterministic boundary cases for
zero, I128_MIN/MAX (exact), just-out-of-range ±1, and oversized values
whose low 128 bits are all zero (expected result: 0n).
Zig 0.16's `zig fmt` reorders `@alignCast(@ptrCast(x))` to
`@ptrCast(@aligncast(x))`. The pre-existing form was triggering format
churn in working trees across every `zig build` invocation; applying
the canonical order once stops the noise.
The seeds-workflow doc claimed NaN/Infinity could be persisted via a
{"__special": ...} encoding, but no corresponding reviver exists in
fuzz.test.ts — following the README literally would silently corrupt
test input. NaN/Infinity are already in edgeNumbers and exercised every
run, so persisting them adds nothing. Trim the README to match reality.
Comment thread .github/workflows/ci.yml
- name: Test
run: pnpm test:js

test-fuzz:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems a little strange to fuzz in CI

@wemeetagain wemeetagain left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the API changes and additional comments are good

# Conflicts:
#	build.zig.zon
#	src/js/bigint.zig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Awaiting Author

Development

Successfully merging this pull request may close these issues.

3 participants