@@ -13,82 +13,90 @@ module RBS
1313 class Parser
1414 class << self
1515 def _parse_signature ( buffer , start_pos , end_pos )
16- validate_position_range ( start_pos , end_pos )
16+ validate_position_range ( buffer , start_pos , end_pos )
1717 encoding = buffer . content . encoding . name
18- success , bytes = WASM ::Runtime . instance . parse_signature ( buffer . content , encoding , start_pos , end_pos )
19- raise_parsing_error ( buffer , bytes ) unless success
18+ status , bytes = WASM ::Runtime . instance . parse_signature ( buffer . content , encoding , start_pos , end_pos )
19+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
2020
2121 WASM ::Deserializer . deserialize ( bytes , buffer )
2222 end
2323
2424 def _parse_type ( buffer , start_pos , end_pos , variables , require_eof , void_allowed , self_allowed , classish_allowed )
25- validate_position_range ( start_pos , end_pos )
25+ validate_position_range ( buffer , start_pos , end_pos )
2626 validate_variables ( variables )
2727 encoding = buffer . content . encoding . name
28- success , bytes = WASM ::Runtime . instance . parse_type ( buffer . content , encoding , start_pos , end_pos , variables , require_eof , void_allowed , self_allowed , classish_allowed )
29- raise_parsing_error ( buffer , bytes ) unless success
28+ status , bytes = WASM ::Runtime . instance . parse_type ( buffer . content , encoding , start_pos , end_pos , variables , require_eof , void_allowed , self_allowed , classish_allowed )
29+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
3030
3131 deserialize_or_nil ( bytes , buffer )
3232 end
3333
3434 def _parse_method_type ( buffer , start_pos , end_pos , variables , require_eof )
35- validate_position_range ( start_pos , end_pos )
35+ validate_position_range ( buffer , start_pos , end_pos )
3636 validate_variables ( variables )
3737 encoding = buffer . content . encoding . name
38- success , bytes = WASM ::Runtime . instance . parse_method_type ( buffer . content , encoding , start_pos , end_pos , variables , require_eof )
39- raise_parsing_error ( buffer , bytes ) unless success
38+ status , bytes = WASM ::Runtime . instance . parse_method_type ( buffer . content , encoding , start_pos , end_pos , variables , require_eof )
39+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
4040
4141 deserialize_or_nil ( bytes , buffer )
4242 end
4343
4444 def _parse_type_params ( buffer , start_pos , end_pos , module_type_params )
45- validate_position_range ( start_pos , end_pos )
45+ validate_position_range ( buffer , start_pos , end_pos )
4646 encoding = buffer . content . encoding . name
47- success , bytes = WASM ::Runtime . instance . parse_type_params ( buffer . content , encoding , start_pos , end_pos , module_type_params )
48- raise_parsing_error ( buffer , bytes ) unless success
47+ status , bytes = WASM ::Runtime . instance . parse_type_params ( buffer . content , encoding , start_pos , end_pos , module_type_params )
48+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
4949
5050 bytes . empty? ? nil : WASM ::Deserializer . deserialize_node_list ( bytes , buffer )
5151 end
5252
5353 def _lex ( buffer , end_pos )
5454 encoding = buffer . content . encoding . name
55- _success , bytes = WASM ::Runtime . instance . lex ( buffer . content , encoding , end_pos )
55+ _status , bytes = WASM ::Runtime . instance . lex ( buffer . content , encoding , end_pos )
5656
5757 WASM ::Deserializer . deserialize_tokens ( bytes , buffer )
5858 end
5959
6060 def _parse_inline_leading_annotation ( buffer , start_pos , end_pos , variables )
61- validate_position_range ( start_pos , end_pos )
61+ validate_position_range ( buffer , start_pos , end_pos )
6262 validate_variables ( variables )
6363 encoding = buffer . content . encoding . name
64- success , bytes = WASM ::Runtime . instance . parse_inline_leading_annotation ( buffer . content , encoding , start_pos , end_pos , variables )
65- raise_parsing_error ( buffer , bytes ) unless success
64+ status , bytes = WASM ::Runtime . instance . parse_inline_leading_annotation ( buffer . content , encoding , start_pos , end_pos , variables )
65+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
6666
6767 deserialize_or_nil ( bytes , buffer )
6868 end
6969
7070 def _parse_inline_trailing_annotation ( buffer , start_pos , end_pos , variables )
71- validate_position_range ( start_pos , end_pos )
71+ validate_position_range ( buffer , start_pos , end_pos )
7272 validate_variables ( variables )
7373 encoding = buffer . content . encoding . name
74- success , bytes = WASM ::Runtime . instance . parse_inline_trailing_annotation ( buffer . content , encoding , start_pos , end_pos , variables )
75- raise_parsing_error ( buffer , bytes ) unless success
74+ status , bytes = WASM ::Runtime . instance . parse_inline_trailing_annotation ( buffer . content , encoding , start_pos , end_pos , variables )
75+ raise_parse_failure ( buffer , status , bytes , start_pos , end_pos ) unless status == WASM :: Runtime :: OK
7676
7777 deserialize_or_nil ( bytes , buffer )
7878 end
7979
8080 private
8181
82- # Reject negative or reversed ranges before handing them to the parser,
83- # matching validate_position_range in the C extension (main.c). A reversed
84- # range would otherwise make the lexer loop forever inside WebAssembly.
85- def validate_position_range ( start_pos , end_pos )
82+ # Reject the position ranges the parser cannot take, matching
83+ # validate_position_range in the C extension (main.c).
84+ #
85+ # `end_pos` past the end of the buffer is fine: clamping with a large
86+ # number instead of measuring the buffer is ordinary, and the lexer stops
87+ # at the end of the input on its own.
88+ def validate_position_range ( buffer , start_pos , end_pos )
8689 if start_pos < 0 || end_pos < 0
8790 raise ArgumentError , "negative position range: #{ start_pos } ...#{ end_pos } "
8891 end
8992 if start_pos > end_pos
9093 raise ArgumentError , "invalid position range: #{ start_pos } ...#{ end_pos } "
9194 end
95+
96+ size = buffer . content . bytesize
97+ if start_pos > size
98+ raise ArgumentError , "position range starts past the end of the buffer: #{ start_pos } ...#{ end_pos } , buffer is #{ size } bytes"
99+ end
92100 end
93101
94102 # Reject anything that is not nil or an Array of Symbols, matching
@@ -112,6 +120,24 @@ def deserialize_or_nil(bytes, buffer)
112120 bytes . empty? ? nil : WASM ::Deserializer . deserialize ( bytes , buffer )
113121 end
114122
123+ # Raise for a status other than OK (see rbs_wasm.c).
124+ #
125+ # A negative status is about the range rather than the source text, so it
126+ # comes with an empty result and an ArgumentError, as in the C extension
127+ # (main.c). Starting past the end of the buffer is plain from the
128+ # buffer's size and rejected above, so a start position that comes back
129+ # rejected can only be one inside a character.
130+ def raise_parse_failure ( buffer , status , bytes , start_pos , end_pos )
131+ case status
132+ when WASM ::Runtime ::INVALID_START_POS
133+ raise ArgumentError , "position range starts inside a character: #{ start_pos } ...#{ end_pos } "
134+ when WASM ::Runtime ::INVALID_RANGE
135+ raise ArgumentError , "invalid position range: #{ start_pos } ...#{ end_pos } "
136+ else
137+ raise_parsing_error ( buffer , bytes )
138+ end
139+ end
140+
115141 # Decodes the error blob written by set_error_result (rbs_wasm.c) and raises
116142 # the same error the C extension would (see raise_error in main.c).
117143 def raise_parsing_error ( buffer , blob )
0 commit comments