Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions crates/blockifier/src/execution/syscalls/hint_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,15 +864,18 @@ where
// If the start and end pointers are the same, the array is empty.
// This check is necessary to handle the case where both pointers are zero, and thus are not
// relocatable values.
let array_start = vm.get_maybe(&*ptr);
if array_start.is_some() && array_start == vm.get_maybe(&(*ptr + 1_usize)?) {
let array_data_start = vm.get_maybe(&*ptr);
let array_data_end = vm.get_maybe(&(*ptr + 1_usize)?);
if array_data_start.is_some() && array_data_start == array_data_end {
*ptr = (*ptr + 2)?;
return Ok(vec![]);
}

let array_data_start_ptr = vm.get_relocatable(*ptr)?;
// This function runs once per array-typed syscall argument, so the endpoints are converted from
// the values read above rather than looked up in memory a second time.
let array_data_start_ptr = relocatable_from_memory_value(array_data_start, *ptr)?;
*ptr = (*ptr + 1)?;
let array_data_end_ptr = vm.get_relocatable(*ptr)?;
let array_data_end_ptr = relocatable_from_memory_value(array_data_end, *ptr)?;
*ptr = (*ptr + 1)?;
let array_size = (array_data_end_ptr - array_data_start_ptr)?;

Expand All @@ -890,3 +893,16 @@ pub fn write_segment(

Ok(())
}

/// Converts a value read from `address` via `VirtualMachine::get_maybe` into a `Relocatable`,
/// reproducing the errors `VirtualMachine::get_relocatable` would have returned for that address.
fn relocatable_from_memory_value(
memory_value: Option<MaybeRelocatable>,
address: Relocatable,
) -> Result<Relocatable, MemoryError> {
match memory_value {
Some(MaybeRelocatable::RelocatableValue(relocatable)) => Ok(relocatable),
Some(MaybeRelocatable::Int(_)) => Err(MemoryError::ExpectedRelocatable(Box::new(address))),
None => Err(MemoryError::UnknownMemoryCell(Box::new(address))),
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use assert_matches::assert_matches;
use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable};
use cairo_vm::vm::errors::memory_errors::MemoryError;
use cairo_vm::vm::vm_core::VirtualMachine;
use starknet_types_core::felt::Felt;

Expand Down Expand Up @@ -69,11 +71,48 @@ fn read_felt_array_accepts_real_empty_span() {
fn read_felt_array_rejects_mixed_null_and_pointer_span() {
let mut vm = VirtualMachine::new(false, false);
let data_ptr = vm.add_memory_segment();
let span_ptr = vm.add_memory_segment();
vm.load_data(span_ptr, &[Felt::ZERO.into(), data_ptr.into()]).unwrap();
let mut span_ptr = span_ptr;
let (vm, mut span_ptr) = vm_with_span_in(vm, Felt::ZERO.into(), data_ptr.into());
let expected_address = span_ptr;

let error = read_felt_array::<SyscallExecutorBaseError>(&vm, &mut span_ptr).unwrap_err();

assert_matches!(
error,
SyscallExecutorBaseError::Memory(MemoryError::ExpectedRelocatable(address))
if *address == expected_address
);
}

#[test]
fn read_felt_array_rejects_span_with_felt_end_pointer() {
// The reported address must be the end pointer's cell, not the span's base.
let mut vm = VirtualMachine::new(false, false);
let data_ptr = vm.add_memory_segment();
let (vm, mut span_ptr) = vm_with_span_in(vm, data_ptr.into(), Felt::ZERO.into());
let expected_address = (span_ptr + 1_usize).unwrap();

let error = read_felt_array::<SyscallExecutorBaseError>(&vm, &mut span_ptr).unwrap_err();

assert_matches!(
error,
SyscallExecutorBaseError::Memory(MemoryError::ExpectedRelocatable(address))
if *address == expected_address
);
}

#[test]
fn read_felt_array_rejects_unwritten_span() {
let mut vm = VirtualMachine::new(false, false);
let mut span_ptr = vm.add_memory_segment();
let expected_address = span_ptr;

let error = read_felt_array::<SyscallExecutorBaseError>(&vm, &mut span_ptr).unwrap_err();

assert!(read_felt_array::<SyscallExecutorBaseError>(&vm, &mut span_ptr).is_err());
assert_matches!(
error,
SyscallExecutorBaseError::Memory(MemoryError::UnknownMemoryCell(address))
if *address == expected_address
);
}

#[test]
Expand Down
Loading