add check memory border while reading/writing memory; improve parsing wat

This commit is contained in:
vms 2020-09-17 20:12:53 +03:00
parent 05c2d9ddda
commit c92344272b
4 changed files with 74 additions and 26 deletions

View File

@ -158,22 +158,34 @@ impl Parse<'_> for RecordType {
fn parse(parser: Parser<'_>) -> Result<Self> {
parser.parse::<keyword::record>()?;
parser.parse::<keyword::string>()?;
let record_name = parser.parse()?;
let record_name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
let mut fields = vec![];
while !parser.is_empty() {
fields.push(parser.parens(|parser| {
parser.parse::<keyword::string>()?;
let name = parser.parse()?;
parser.parens(|parser| {
while !parser.is_empty() {
parser.parse::<keyword::field>()?;
let name = parser
.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?
.to_string();
let ty = parser.parse()?;
Ok(RecordFieldType { name, ty })
})?);
}
fields.push(RecordFieldType { name, ty });
}
Ok(())
})?;
Ok(RecordType {
name: record_name,

View File

@ -77,7 +77,7 @@ impl ToString for &InterfaceType {
InterfaceType::Anyref => "anyref".to_string(),
InterfaceType::I32 => "i32".to_string(),
InterfaceType::I64 => "i64".to_string(),
InterfaceType::Record(record_type) => record_type.to_string(),
InterfaceType::Record(record_type_id) => format!("record {}", record_type_id),
}
}
}
@ -85,7 +85,7 @@ impl ToString for &InterfaceType {
impl ToString for &RecordType {
fn to_string(&self) -> String {
format!(
"record {} {{\n{fields}}}",
"record ${} {{\n{fields}}}",
self.name,
fields = self
.fields
@ -93,7 +93,7 @@ impl ToString for &RecordType {
.fold(String::new(), |mut accumulator, field_type| {
accumulator.push(' ');
accumulator.push_str(&format!(
"{}: {}\n",
"field ${}: {}\n",
field_type.name,
(&field_type.ty).to_string()
));

View File

@ -284,6 +284,12 @@ where
)
})?;
log::trace!(
"record.lift_memory: record {:?} resolved for type id {}",
record_type,
record_type_id
);
let record = record_lift_memory_(&**instance, record_type, offset, instruction)?;
log::trace!("record.lift_memory: pushing {:?} on the stack", record);
@ -327,7 +333,7 @@ where
let string_pointer = if !value.is_empty() {
write_to_instance_mem(instance, instruction, value.as_bytes())?
} else {
0i32
0
};
result.push(string_pointer as _);
@ -338,7 +344,7 @@ where
let byte_array_pointer = if !value.is_empty() {
write_to_instance_mem(instance, instruction, &value)?
} else {
0i32
0
};
result.push(byte_array_pointer as _);
@ -348,7 +354,6 @@ where
InterfaceValue::Record(values) => {
let record_ptr = record_lower_memory_(instance, instruction, values)?;
log::trace!("record.lower_memory: pushing {:?} on the stack", record_ptr);
result.push(record_ptr as _);
}
}
@ -357,7 +362,7 @@ where
let result = safe_transmute::transmute_to_bytes::<u64>(&result);
let result_pointer = write_to_instance_mem(instance, instruction, &result)?;
Ok(result_pointer)
Ok(result_pointer as _)
}
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
@ -386,7 +391,12 @@ where
&record_fields,
instruction,
)?;
log::trace!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id);
let offset = record_lower_memory_(*instance, instruction, record_fields)?;
log::trace!("record.lower_memory: pushing {:?} on the stack", offset);
runtime.stack.push(InterfaceValue::I32(offset));
Ok(())

View File

@ -35,6 +35,19 @@ where
})?
.view();
log::info!("reading {} bytes from offset {}", size, offset);
let right = offset + size;
if right < offset || right >= memory_view.len() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: right,
length: memory_view.len(),
},
));
}
Ok((&memory_view[offset..offset + size])
.iter()
.map(std::cell::Cell::get)
@ -45,7 +58,7 @@ pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Me
instance: &'instance Instance,
instruction: Instruction,
bytes: &[u8],
) -> Result<i32, InstructionError>
) -> Result<usize, InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
@ -53,7 +66,7 @@ where
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let mem_pointer = allocate(instance, instruction, bytes.len() as _)?;
let offset = allocate(instance, instruction, bytes.len() as _)?;
let memory_index: u32 = 0;
let memory_view = instance
@ -66,18 +79,31 @@ where
})?
.view();
for (byte_id, byte) in bytes.iter().enumerate() {
memory_view[mem_pointer as usize + byte_id].set(*byte);
log::info!("writing {} bytes from offset {}", bytes.len(), offset);
let right = offset + bytes.len();
if right < offset || right >= memory_view.len() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: right,
length: memory_view.len(),
},
));
}
Ok(mem_pointer)
for (byte_id, byte) in bytes.iter().enumerate() {
memory_view[offset + byte_id].set(*byte);
}
Ok(offset)
}
pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
size: i32,
) -> Result<i32, InstructionError>
size: usize,
) -> Result<usize, InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
@ -89,7 +115,7 @@ where
instance,
ALLOCATE_FUNC_INDEX,
instruction,
vec![InterfaceValue::I32(size)],
vec![InterfaceValue::I32(size as _)],
)?;
if values.len() != 1 {
return Err(InstructionError::new(
@ -101,7 +127,7 @@ where
},
));
}
to_native::<i32>(&values[0], instruction)
to_native::<i32>(&values[0], instruction).map(|v| v as usize)
}
pub(super) fn deallocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(