diff --git a/crates/blockifier/src/execution/syscalls/hint_processor.rs b/crates/blockifier/src/execution/syscalls/hint_processor.rs index 9da8f4fa687..2d2066e90a8 100644 --- a/crates/blockifier/src/execution/syscalls/hint_processor.rs +++ b/crates/blockifier/src/execution/syscalls/hint_processor.rs @@ -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)?; @@ -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, + address: Relocatable, +) -> Result { + 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))), + } +} diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/null_empty_span.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/null_empty_span.rs index f728933efd1..161c9b2ca83 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/null_empty_span.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/null_empty_span.rs @@ -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; @@ -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::(&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::(&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::(&vm, &mut span_ptr).unwrap_err(); - assert!(read_felt_array::(&vm, &mut span_ptr).is_err()); + assert_matches!( + error, + SyscallExecutorBaseError::Memory(MemoryError::UnknownMemoryCell(address)) + if *address == expected_address + ); } #[test]