@@ -250,21 +250,8 @@ fn parse_function_body(
250250 builder. set_srcloc ( cur_srcloc ( & reader. get_binary_reader ( ) ) ) ;
251251
252252 let op = reader. read ( ) ?;
253-
254- // Get the operand types for this operator.
255- let arity = op. operator_arity ( & * validator) ;
256- operand_types. clear ( ) ;
257- let operand_types = arity. and_then ( |( operand_arity, _result_arity) | {
258- for i in ( 0 ..operand_arity) . rev ( ) {
259- let i = usize:: try_from ( i) . unwrap ( ) ;
260- let ty = validator. get_operand_type ( i) ??;
261- let ty = environ. convert_valtype ( ty) . ok ( ) ?;
262- operand_types. push ( ty) ;
263- }
264- Some ( & operand_types[ ..] )
265- } ) ;
266-
267- validator. op ( pos, & op) ?;
253+ let operand_types =
254+ validate_op_and_get_operand_types ( validator, environ, & mut operand_types, & op, pos) ?;
268255
269256 environ. before_translate_operator ( & op, operand_types, builder, state) ?;
270257 translate_operator ( validator, & op, operand_types, builder, state, environ) ?;
@@ -293,6 +280,40 @@ fn parse_function_body(
293280 Ok ( ( ) )
294281}
295282
283+ fn validate_op_and_get_operand_types < ' a > (
284+ validator : & mut FuncValidator < impl WasmModuleResources > ,
285+ environ : & mut FuncEnvironment < ' _ > ,
286+ operand_types : & ' a mut Vec < wasmtime_environ:: WasmValType > ,
287+ op : & wasmparser:: Operator < ' _ > ,
288+ pos : usize ,
289+ ) -> WasmResult < Option < & ' a [ wasmtime_environ:: WasmValType ] > > {
290+ // Get the operand types for this operator.
291+ //
292+ // Note that we don't know if the `op` is valid yet, but only valid ops will
293+ // definitely have arity. However, we also must check the arity before
294+ // validating the op so that the validator has the right state to correctly
295+ // report the arity. Furthermore, even if the op is valid, if it is in
296+ // unreachable code, the op might want to pop more values from the stack
297+ // than actually exist on the stack (which is allowed in unreachable code)
298+ // so even if we can get arity, we are only guaranteed to have operand types
299+ // for ops that are not only valid but also reachable.
300+ let arity = op. operator_arity ( & * validator) ;
301+ operand_types. clear ( ) ;
302+ let operand_types = arity. and_then ( |( operand_arity, _result_arity) | {
303+ for i in ( 0 ..operand_arity) . rev ( ) {
304+ let i = usize:: try_from ( i) . unwrap ( ) ;
305+ let ty = validator. get_operand_type ( i) ??;
306+ let ty = environ. convert_valtype ( ty) . ok ( ) ?;
307+ operand_types. push ( ty) ;
308+ }
309+ Some ( & operand_types[ ..] )
310+ } ) ;
311+
312+ validator. op ( pos, & op) ?;
313+
314+ Ok ( operand_types)
315+ }
316+
296317/// Get the current source location from a reader.
297318fn cur_srcloc ( reader : & BinaryReader ) -> ir:: SourceLoc {
298319 // We record source locations as byte code offsets relative to the beginning of the file.
0 commit comments