Skip to content

Handle the NULL parser in the WebAssembly shim - #3085

Merged
soutaro merged 2 commits into
masterfrom
claude/jruby-pr-3083-null-issue-0s30d5
Aug 12, 2026
Merged

Handle the NULL parser in the WebAssembly shim#3085
soutaro merged 2 commits into
masterfrom
claude/jruby-pr-3083-null-issue-0s30d5

Conversation

@soutaro

@soutaro soutaro commented Aug 12, 2026

Copy link
Copy Markdown
Member

JRuby has been failing on master since #3083.

That PR made rbs_parser_new return NULL for a start_pos that no character starts at, but the WebAssembly shim uses the result unchecked. Address 0 is ordinary memory in a linear-memory module, so nothing traps: it returns a parse failure with an empty result, and decoding that as an error blob is the undefined method 'zero?' for nil in the three RBS::TypeParsingTest failures.

The shim now checks for NULL and reports it as RBS_WASM_INVALID_START_POS, which RBS::Parser turns into the same ArgumentError the C extension raises. It also clamps end_pos to the buffer instead of rejecting anything past the end, so byte_range: 0...9999 parses on JRuby as it does on CRuby.

The three tests #3083 added cover this, and they run on JRuby.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AqEsvUoBfRtqECvrGRWTpy

claude added 2 commits August 12, 2026 07:44
#3083 made `rbs_lexer_new` and `rbs_parser_new` return `NULL` for a
`start_pos` the lexer cannot start on, and taught the C extension to raise
`ArgumentError` for it. The WebAssembly shim went on using the result
unchecked: linear memory has no protected page at address 0, so nothing traps
there -- the module reads and writes whatever sits at offset 0 and returns a
parse failure with an empty result, which the Ruby side then tries to decode as
an error blob. That is the `undefined method 'zero?' for nil` behind the three
JRuby failures in `RBS::TypeParsingTest`.

So the shim checks for `NULL` and reports it: the parse entry points gain a
status of their own for a `start_pos` the parser will not take, and
`RBS::Parser` turns it into the same `ArgumentError` the extension raises.
Negative and reversed ranges get a status too, rather than the parse-error one
they shared with an empty blob.

The `end_pos` rule had to move as well. The extension takes any `end_pos` --
clamping with a large number instead of measuring the buffer is ordinary, and
the lexer stops at the end of the input on its own, because a Ruby string keeps
a NUL terminator to stop at. A buffer the host wrote into linear memory has
nothing behind it, so the shim rejected anything past the end instead. It now
clamps to the buffer, which is the same position the extension stops at, and
`parse_type("Integer", byte_range: 0...9999)` parses on JRuby as it does on
CRuby.

Verified by compiling the shim natively against `src/` under ASan/UBSan (it is
plain C) and driving the entry points over exact-sized allocations: the ranges
above return their statuses with no read past the end of the buffer, and the
pre-fix shim reports the null dereference at `rbs_wasm_parse_type`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqEsvUoBfRtqECvrGRWTpy
`UNREACHABLE_START` described how the lexer finds the bad position -- it walks
a character at a time and never lands on it -- rather than what the caller did.
`INVALID_START_POS` says the fact, and reads alongside `INVALID_RANGE`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqEsvUoBfRtqECvrGRWTpy
@soutaro
soutaro added this pull request to the merge queue Aug 12, 2026
Merged via the queue into master with commit e5c20ae Aug 12, 2026
25 checks passed
@soutaro
soutaro deleted the claude/jruby-pr-3083-null-issue-0s30d5 branch August 12, 2026 08:15
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