ruby / ruby/rbs

Malformed class instance variable member raises RuntimeError instead of RBS::ParsingError

Open
#3,148 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
2.2k
Forks
256
Avg merge
6d 17h
Merged PRs (30d)
37

Description

Summary

A malformed class instance variable member raises RuntimeError instead of RBS::ParsingError, so it escapes rescue RBS::ParsingError and the CLI prints a raw Ruby backtrace instead of a formatted syntax error.

require "rbs"
RBS::Parser.parse_signature(RBS::Buffer.new(name: "test.rbs", content: "class M self."))
lib/rbs/parser_aux.rb:31:in 'RBS::Parser._parse_signature': Unexpected error (RuntimeError)

Every other syntax error in the same position is reported correctly, which is what makes this stand out:

input raised
class M <<< RBS::ParsingError with location and caret
class M self. RuntimeError: Unexpected error
module M self. RuntimeError: Unexpected error
class M self.5 RuntimeError: Unexpected error
class M self."x" RuntimeError: Unexpected error
interface _I self. RBS::ParsingError
class M\n self.@x: Integer\nend parses fine (valid)

Note that interface already reports this correctly — only the class/module path is affected.

Impact

RBS::ParsingError is the documented error class for malformed signatures, so a caller that rescues it does not catch this:

begin
  RBS::Parser.parse_signature(buffer)
rescue RBS::ParsingError => e
  # never reached for "class M self."
end

The CLI is affected the same way. Compare:

$ rbs parse normal.rbs
/tmp/normal.rbs:1:8...1:10: Syntax error: unexpected token for class/module declaration member, token=`<<` (tOPERATOR) (RBS::ParsingError)

  class M <<<
          ^^

$ rbs parse bug.rbs
lib/rbs/parser_aux.rb:31:in 'RBS::Parser._parse_signature': Unexpected error (RuntimeError)
	from lib/rbs/cli.rb:943:in 'block in RBS::CLI#run_parse'
	...

Cause

src/parser.c:2353, in the kSELF branch of parse_variable_member:

rbs_parser_set_error(parser, parser->current_token, false, "Unexpected error");

The third argument is bool syntax_error (include/rbs/parser.h:161). It is passed false, so ext/rbs_extension/main.c discards the location, token and message:

if (!error->syntax_error) {
    rb_raise(rb_eRuntimeError, "Unexpected error");
}

For comparison, 49 other call sites in src/parser.c pass true and produce proper RBS::ParsingErrors.

I checked whether the other 12 false sites have the same problem, by tagging each one and fuzzing: they are defensive default: arms over already-exhausted enums and are not reachable from user input, so RuntimeError is the right semantic there. This is the only reachable one.

Environment

master cc0b38dfebd0de1f5941c1257a72e0ffc7e1c7bc. Also reproduces on released gems 4.2.0, 4.1.3, 4.0.3 and 3.10.0.

I have a patch and will open a PR referencing this issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the kSELF branch of parse_variable_member in src/parser.c:2353, then read the syntax_error parameter in include/rbs/parser.h:161 and its handling in ext/rbs_extension/main.c. Reproduce the listed malformed signatures and confirm they raise RBS::ParsingError with location information and that the CLI prints a formatted syntax error.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, ruby
Domain
compilers, tooling
Issue type
Bug
Difficulty
1/5
Estimated time
Under an hour
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.