Handle the NULL parser in the WebAssembly shim - #3085
Merged
Conversation
#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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
JRuby has been failing on master since #3083.
That PR made
rbs_parser_newreturnNULLfor astart_posthat 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 theundefined method 'zero?' for nilin the threeRBS::TypeParsingTestfailures.The shim now checks for
NULLand reports it asRBS_WASM_INVALID_START_POS, whichRBS::Parserturns into the sameArgumentErrorthe C extension raises. It also clampsend_posto the buffer instead of rejecting anything past the end, sobyte_range: 0...9999parses 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