@@ -146,44 +146,66 @@ static VALUE parse_type_try(VALUE a) {
146146 return rbs_struct_to_ruby_value (ctx , type );
147147}
148148
149- static void validate_position_range (int start_pos , int end_pos ) {
149+ /**
150+ * `end_pos` may point past the end of the buffer: clamping with a large
151+ * number instead of measuring the buffer is ordinary, and the lexer stops at
152+ * the end on its own.
153+ * */
154+ static void validate_position_range (VALUE string , int start_pos , int end_pos ) {
150155 if (start_pos < 0 || end_pos < 0 ) {
151156 rb_raise (rb_eArgError , "negative position range: %d...%d" , start_pos , end_pos );
152157 }
153158 if (start_pos > end_pos ) {
154159 rb_raise (rb_eArgError , "invalid position range: %d...%d" , start_pos , end_pos );
155160 }
161+
162+ long size = RSTRING_LEN (string );
163+ if ((long ) start_pos > size ) {
164+ rb_raise (rb_eArgError , "position range starts past the end of the buffer: %d...%d, buffer is %ld bytes" , start_pos , end_pos , size );
165+ }
156166}
157167
158168static rbs_lexer_t * alloc_lexer_from_buffer (rbs_allocator_t * allocator , VALUE string , rb_encoding * encoding , int start_pos , int end_pos ) {
159- validate_position_range (start_pos , end_pos );
169+ validate_position_range (string , start_pos , end_pos );
160170
161171 const char * encoding_name = rb_enc_name (encoding );
162172
163- return rbs_lexer_new (
173+ rbs_lexer_t * lexer = rbs_lexer_new (
164174 allocator ,
165175 rbs_string_from_ruby_string (string ),
166176 rbs_encoding_find ((const uint8_t * ) encoding_name , (const uint8_t * ) (encoding_name + strlen (encoding_name ))),
167177 start_pos ,
168178 end_pos
169179 );
180+
181+ if (lexer == NULL ) {
182+ rb_raise (rb_eArgError , "position range starts inside a character: %d...%d" , start_pos , end_pos );
183+ }
184+
185+ return lexer ;
170186}
171187
172188static rbs_parser_t * alloc_parser_from_buffer (VALUE buffer , int start_pos , int end_pos ) {
173- validate_position_range (start_pos , end_pos );
174-
175189 VALUE string = rb_funcall (buffer , rb_intern ("content" ), 0 );
176190 StringValue (string );
177191
192+ validate_position_range (string , start_pos , end_pos );
193+
178194 rb_encoding * encoding = rb_enc_get (string );
179195 const char * encoding_name = rb_enc_name (encoding );
180196
181- return rbs_parser_new (
197+ rbs_parser_t * parser = rbs_parser_new (
182198 rbs_string_from_ruby_string (string ),
183199 rbs_encoding_find ((const uint8_t * ) encoding_name , (const uint8_t * ) (encoding_name + strlen (encoding_name ))),
184200 start_pos ,
185201 end_pos
186202 );
203+
204+ if (parser == NULL ) {
205+ rb_raise (rb_eArgError , "position range starts inside a character: %d...%d" , start_pos , end_pos );
206+ }
207+
208+ return parser ;
187209}
188210
189211static VALUE rbsparser_parse_type (VALUE self , VALUE buffer , VALUE start_pos , VALUE end_pos , VALUE variables , VALUE require_eof , VALUE void_allowed , VALUE self_allowed , VALUE classish_allowed ) {
0 commit comments