Skip to content

Comments

Fix incorrect NaN payload values in isCanonicalNaN and isArithmeticNaN#8350

Open
sumleo wants to merge 2 commits intoWebAssembly:mainfrom
sumleo:fix-nan-payload-values
Open

Fix incorrect NaN payload values in isCanonicalNaN and isArithmeticNaN#8350
sumleo wants to merge 2 commits intoWebAssembly:mainfrom
sumleo:fix-nan-payload-values

Conversation

@sumleo
Copy link
Contributor

@sumleo sumleo commented Feb 20, 2026

Summary

  • Fix isCanonicalNaN to check for the correct canonical NaN payload per the wasm spec: 1 << 22 (0x400000) for f32 and 1ull << 51 (0x8000000000000) for f64, instead of the incorrect (1 << 23) - 1 (0x7FFFFF) and (1ull << 52) - 1.
  • Fix isArithmeticNaN to check whether the quiet bit is set in the payload (bit 22 for f32, bit 51 for f64), instead of the impossible payload > max_payload comparison that could never be true.

Details

The wasm spec defines:

  • Canonical NaN: a NaN with only the quiet bit set in the significand. For f32 this is nan:0x400000, for f64 this is nan:0x8000000000000.
  • Arithmetic NaN: any NaN with the quiet bit set (i.e., any quiet NaN).

The previous isCanonicalNaN checked if the payload equaled the maximum 23-bit value (all bits set), which is not what the spec requires. The previous isArithmeticNaN compared payload > (1u << 23) - 1, but since 0x7FFFFF is already the maximum possible 23-bit payload, this could never return true.

This fix should enable un-skipping the f32.wast, f64.wast, and float_exprs.wast spec tests, which are currently skipped in scripts/test/shared.py because of this bug.

Test plan

  • All 309 unit tests pass (binaryen-unittests)
  • wasm-shell test/spec/testsuite/f32.wast - all checks passed
  • wasm-shell test/spec/testsuite/f64.wast - all checks passed
  • wasm-shell test/spec/testsuite/float_exprs.wast - all checks passed

The wasm spec defines a canonical NaN as having only the quiet bit set
in the significand (bit 22 for f32, bit 51 for f64), giving payloads of
0x400000 and 0x8000000000000 respectively. The previous code checked for
the maximum possible payload ((1 << 23) - 1 = 0x7FFFFF for f32), which
is not what the spec requires.

Similarly, isArithmeticNaN checked payload > max_payload, which could
never be true. Per the spec, an arithmetic NaN is any NaN with the quiet
bit set, so the correct check is whether the quiet bit is set in the
payload.

These fixes allow f32.wast, f64.wast, and float_exprs.wast spec tests
to pass, which were previously skipped due to this bug.
@kripken
Copy link
Member

kripken commented Feb 21, 2026

Please un-skip those tests, now that they pass. That will also serve as testing for the PR.

@sumleo
Copy link
Contributor Author

sumleo commented Feb 21, 2026

Done — un-skipped f32.wast, f64.wast, and float_exprs.wast. All three pass with the NaN fix.

@sumleo sumleo force-pushed the fix-nan-payload-values branch from 8efe63e to 4228af0 Compare February 21, 2026 02:36
The original skip reasons cited incorrect NaN canonicality checks,
which are now fixed by the isCanonicalNaN/isArithmeticNaN changes.
However, these tests still fail on Linux due to platform-dependent
NaN propagation where arithmetic operations can produce signaling
NaNs instead of quiet NaNs. Update the skip comments accordingly.
@sumleo sumleo force-pushed the fix-nan-payload-values branch from 4228af0 to 344b47f Compare February 21, 2026 04:12
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.

2 participants