Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions ext/rbs_extension/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,17 @@ static VALUE parse_type_try(VALUE a) {
return rbs_struct_to_ruby_value(ctx, type);
}

static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE string, rb_encoding *encoding, int start_pos, int end_pos) {
static void validate_position_range(int start_pos, int end_pos) {
if (start_pos < 0 || end_pos < 0) {
rb_raise(rb_eArgError, "negative position range: %d...%d", start_pos, end_pos);
}
if (start_pos > end_pos) {
rb_raise(rb_eArgError, "invalid position range: %d...%d", start_pos, end_pos);
}
}

static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE string, rb_encoding *encoding, int start_pos, int end_pos) {
validate_position_range(start_pos, end_pos);

const char *encoding_name = rb_enc_name(encoding);

Expand All @@ -162,9 +169,7 @@ static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE st
}

static rbs_parser_t *alloc_parser_from_buffer(VALUE buffer, int start_pos, int end_pos) {
if (start_pos < 0 || end_pos < 0) {
rb_raise(rb_eArgError, "negative position range: %d...%d", start_pos, end_pos);
}
validate_position_range(start_pos, end_pos);

VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
StringValue(string);
Expand Down
15 changes: 15 additions & 0 deletions test/rbs/parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,21 @@ class Foo[T < Integer] < Bar # Comment
assert_equal [:pEOF, '', 57...57], tokens.shift.then { |t| [t[0], t[1].source, t[1].range] }
end

def test_invalid_position_range_raises
# Regression: start_pos > end_pos used to cause an infinite loop in the lexer.
assert_raises(ArgumentError) do
RBS::Parser._parse_signature(buffer(""), 1, 0)
end
end

def test_invalid_byte_range_in_parse_type_raises
# Regression: parse_type's byte_range: keyword reaches _parse_type directly,
# which used to hang on reversed ranges.
assert_raises(ArgumentError) do
RBS::Parser.parse_type("", byte_range: 1..0)
end
end

def test_invalid_utf8_byte_in_comment_does_not_hang
# Regression: invalid UTF-8 byte in a comment used to loop forever in the lexer.
source = "# \xC2".dup.force_encoding(Encoding::UTF_8)
Expand Down
Loading