Skip to content

Commit 204211c

Browse files
authored
Merge pull request #2974 from ksss/ksss/fix-invalid-position-range
Reject reversed position ranges in parser/lexer entrypoints
2 parents 88597ed + 9ebddb0 commit 204211c

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

ext/rbs_extension/main.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,17 @@ static VALUE parse_type_try(VALUE a) {
145145
return rbs_struct_to_ruby_value(ctx, type);
146146
}
147147

148-
static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE string, rb_encoding *encoding, int start_pos, int end_pos) {
148+
static void validate_position_range(int start_pos, int end_pos) {
149149
if (start_pos < 0 || end_pos < 0) {
150150
rb_raise(rb_eArgError, "negative position range: %d...%d", start_pos, end_pos);
151151
}
152+
if (start_pos > end_pos) {
153+
rb_raise(rb_eArgError, "invalid position range: %d...%d", start_pos, end_pos);
154+
}
155+
}
156+
157+
static rbs_lexer_t *alloc_lexer_from_buffer(rbs_allocator_t *allocator, VALUE string, rb_encoding *encoding, int start_pos, int end_pos) {
158+
validate_position_range(start_pos, end_pos);
152159

153160
const char *encoding_name = rb_enc_name(encoding);
154161

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

164171
static rbs_parser_t *alloc_parser_from_buffer(VALUE buffer, int start_pos, int end_pos) {
165-
if (start_pos < 0 || end_pos < 0) {
166-
rb_raise(rb_eArgError, "negative position range: %d...%d", start_pos, end_pos);
167-
}
172+
validate_position_range(start_pos, end_pos);
168173

169174
VALUE string = rb_funcall(buffer, rb_intern("content"), 0);
170175
StringValue(string);

test/rbs/parser_test.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,21 @@ class Foo[T < Integer] < Bar # Comment
10301030
assert_equal [:pEOF, '', 57...57], tokens.shift.then { |t| [t[0], t[1].source, t[1].range] }
10311031
end
10321032

1033+
def test_invalid_position_range_raises
1034+
# Regression: start_pos > end_pos used to cause an infinite loop in the lexer.
1035+
assert_raises(ArgumentError) do
1036+
RBS::Parser._parse_signature(buffer(""), 1, 0)
1037+
end
1038+
end
1039+
1040+
def test_invalid_byte_range_in_parse_type_raises
1041+
# Regression: parse_type's byte_range: keyword reaches _parse_type directly,
1042+
# which used to hang on reversed ranges.
1043+
assert_raises(ArgumentError) do
1044+
RBS::Parser.parse_type("", byte_range: 1..0)
1045+
end
1046+
end
1047+
10331048
def test_invalid_utf8_byte_in_comment_does_not_hang
10341049
# Regression: invalid UTF-8 byte in a comment used to loop forever in the lexer.
10351050
source = "# \xC2".dup.force_encoding(Encoding::UTF_8)

0 commit comments

Comments
 (0)