Skip to content

Commit 884c2cf

Browse files
authored
Validate block parameters (bytecodealliance#123)
also fixes read_var_s33()
1 parent 380b5b7 commit 884c2cf

2 files changed

Lines changed: 53 additions & 16 deletions

File tree

src/binary_reader.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -535,20 +535,35 @@ impl<'a> BinaryReader<'a> {
535535
}
536536

537537
pub fn read_var_s33(&mut self) -> Result<i64> {
538-
// Note: this is not quite spec compliant, in that it doesn't enforce
539-
// that the number is encoded in ceil(N / 7) bytes. We should make a
540-
// generic-over-N decoding function and replace all the various
541-
// `read_var_{i,s}NN` methods with calls to instantiations of that.
538+
// Optimization for single byte.
539+
let byte = self.read_u8()?;
540+
if (byte & 0x80) == 0 {
541+
return Ok(((byte as i8) << 1) as i64 >> 1);
542+
}
542543

543-
let n = self.read_var_i64()?;
544-
if n > (1 << 33 - 1) {
545-
Err(BinaryReaderError {
546-
message: "Invalid var_s33",
547-
offset: self.original_position() - 1,
548-
})
549-
} else {
550-
Ok(n)
544+
let mut result = (byte & 0x7F) as i64;
545+
let mut shift = 7;
546+
loop {
547+
let byte = self.read_u8()?;
548+
result |= ((byte & 0x7F) as i64) << shift;
549+
if shift >= 25 {
550+
let continuation_bit = (byte & 0x80) != 0;
551+
let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);
552+
if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
553+
return Err(BinaryReaderError {
554+
message: "Invalid var_i33",
555+
offset: self.original_position() - 1,
556+
});
557+
}
558+
return Ok(result);
559+
}
560+
shift += 7;
561+
if (byte & 0x80) == 0 {
562+
break;
563+
}
551564
}
565+
let ashift = 64 - shift;
566+
Ok((result << ashift) >> ashift)
552567
}
553568

554569
pub fn read_var_i64(&mut self) -> Result<i64> {

src/operators_validator.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,10 +550,7 @@ impl OperatorValidator {
550550
return Err("type index out of bounds");
551551
}
552552
let ty = &types[idx];
553-
if self.config.enable_multi_value {
554-
// TODO implement proper validation that includes params
555-
// similar to `self.check_operands(&ty.params)?;`
556-
} else {
553+
if !self.config.enable_multi_value {
557554
if ty.returns.len() > 1 {
558555
return Err("blocks, loops, and ifs may only return at most one \
559556
value when multi-value is not enabled");
@@ -569,6 +566,28 @@ impl OperatorValidator {
569566
}
570567
}
571568

569+
fn check_block_params(
570+
&self,
571+
ty: TypeOrFuncType,
572+
resources: &dyn WasmModuleResources,
573+
skip: usize,
574+
) -> OperatorValidatorResult<()> {
575+
if let TypeOrFuncType::FuncType(idx) = ty {
576+
let func_ty = &resources.types()[idx as usize];
577+
let len = func_ty.params.len();
578+
self.check_frame_size(len + skip)?;
579+
for i in 0..len {
580+
if !self
581+
.func_state
582+
.assert_stack_type_at(len - 1 - i + skip, func_ty.params[i])
583+
{
584+
return Err("stack operand type mismatch for block");
585+
}
586+
}
587+
}
588+
Ok(())
589+
}
590+
572591
fn check_select(&self) -> OperatorValidatorResult<Option<Type>> {
573592
self.check_frame_size(3)?;
574593
let func_state = &self.func_state;
@@ -610,16 +629,19 @@ impl OperatorValidator {
610629
Operator::Nop => (),
611630
Operator::Block { ty } => {
612631
self.check_block_type(ty, resources)?;
632+
self.check_block_params(ty, resources, 0)?;
613633
self.func_state
614634
.push_block(ty, BlockType::Block, resources)?;
615635
}
616636
Operator::Loop { ty } => {
617637
self.check_block_type(ty, resources)?;
638+
self.check_block_params(ty, resources, 0)?;
618639
self.func_state.push_block(ty, BlockType::Loop, resources)?;
619640
}
620641
Operator::If { ty } => {
621642
self.check_block_type(ty, resources)?;
622643
self.check_operands_1(Type::I32)?;
644+
self.check_block_params(ty, resources, 1)?;
623645
self.func_state.push_block(ty, BlockType::If, resources)?;
624646
}
625647
Operator::Else => {

0 commit comments

Comments
 (0)