Skip to content

Commit 96cfd47

Browse files
feat: implemented prevent_segment_execution function
Signed-off-by: Dori Medini <[email protected]>
1 parent fc100d9 commit 96cfd47

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#### Upcoming Changes
44

5+
* feat: implemented prevent_segment_execution function [#2099](https://github.com/lambdaclass/cairo-vm/pull/2099)
6+
57
#### [2.1.0] - 2025-05-21
68

79
* chore: bump pip `cairo-lang` 0.13.5 [#1959](https://github.com/lambdaclass/cairo-vm/pull/1959)

vm/src/vm/errors/memory_errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use crate::types::{
1515

1616
#[derive(Debug, PartialEq, Error)]
1717
pub enum MemoryError {
18+
#[error("Segment {0} has already been accessed; it cannot be execution-protected.")]
19+
SegmentAlreadyAccessed(usize),
1820
#[error(transparent)]
1921
Math(#[from] MathError),
2022
#[error(transparent)]

vm/src/vm/vm_core.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,14 @@ impl VirtualMachine {
946946
self.segments.memory.insert_value(key, val)
947947
}
948948

949+
/// Set the first cell of the given segment to a value that is not a valid opcode, to prevent
950+
/// segment execution. Returns an error if the first cell of the segment is already accessed.
951+
pub fn prevent_segment_execution(&mut self, segment_index: isize) -> Result<(), MemoryError> {
952+
self.segments
953+
.memory
954+
.prevent_segment_execution(segment_index)
955+
}
956+
949957
///Writes data into the memory from address ptr and returns the first address after the data.
950958
pub fn load_data(
951959
&mut self,
@@ -1359,6 +1367,7 @@ mod tests {
13591367
use crate::types::instruction::OpcodeExtension;
13601368
use crate::types::layout_name::LayoutName;
13611369
use crate::types::program::Program;
1370+
use crate::vm::vm_memory::memory::MemoryCell;
13621371
use crate::{
13631372
any_box,
13641373
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{
@@ -4727,6 +4736,48 @@ mod tests {
47274736
assert_eq!(vm.segments.compute_effective_sizes(), &vec![4]);
47284737
}
47294738

4739+
#[test]
4740+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
4741+
fn test_prevent_segment_execution() {
4742+
let mut vm = vm!();
4743+
4744+
let segment0 = vm.segments.add();
4745+
let segment1 = vm.segments.add();
4746+
let segment2 = vm.segments.add();
4747+
let tmp_segment = vm.add_temporary_segment();
4748+
assert_eq!(segment0.segment_index, 0);
4749+
assert_eq!(segment1.segment_index, 1);
4750+
assert_eq!(segment2.segment_index, 2);
4751+
assert_eq!(tmp_segment.segment_index, -1);
4752+
vm.segments.memory = memory![
4753+
((0, 1), 1),
4754+
((1, 0), 3),
4755+
((1, 1), 4),
4756+
((2, 0), 7),
4757+
((-1, 0), 5)
4758+
];
4759+
4760+
vm.mark_address_range_as_accessed((2, 0).into(), 1).unwrap();
4761+
4762+
vm.prevent_segment_execution(0).unwrap();
4763+
vm.prevent_segment_execution(1).unwrap();
4764+
vm.prevent_segment_execution(-1).unwrap();
4765+
4766+
let non_opcode = MemoryCell::new(MaybeRelocatable::Int(Felt252::from(-1)));
4767+
4768+
assert_eq!(vm.segments.memory.data[0][0], non_opcode);
4769+
assert_eq!(vm.segments.memory.data[1][0], non_opcode);
4770+
assert_eq!(vm.segments.memory.temp_data[0][0], non_opcode);
4771+
assert_matches!(
4772+
vm.prevent_segment_execution(2).unwrap_err(),
4773+
MemoryError::SegmentAlreadyAccessed(idx) if idx == 2
4774+
);
4775+
assert_matches!(
4776+
vm.prevent_segment_execution(7).unwrap_err(),
4777+
MemoryError::UnallocatedSegment(boxed) if *boxed == (7, 3)
4778+
);
4779+
}
4780+
47304781
#[test]
47314782
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
47324783
fn mark_as_accessed() {

vm/src/vm/vm_memory/memory.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,37 @@ impl Memory {
237237
self.validate_memory_cell(key)
238238
}
239239

240+
/// Set the first cell of the given segment to a value that is not a valid opcode, to prevent
241+
/// segment execution. Returns an error if the first cell of the segment is already accessed.
242+
pub fn prevent_segment_execution(&mut self, segment_index: isize) -> Result<(), MemoryError> {
243+
let key = Relocatable::from((segment_index, 0));
244+
let data = if segment_index.is_negative() {
245+
&mut self.temp_data
246+
} else {
247+
&mut self.data
248+
};
249+
let (segment_uindex, _) = from_relocatable_to_indexes(key);
250+
251+
let data_len = data.len();
252+
let segment = data
253+
.get_mut(segment_uindex)
254+
.ok_or_else(|| MemoryError::UnallocatedSegment(Box::new((segment_uindex, data_len))))?;
255+
256+
// Check if the segment has at least one cell. If so, check that the first cell has not been
257+
// accessed.
258+
if !segment.is_empty() && segment[0].is_accessed() {
259+
return Err(MemoryError::SegmentAlreadyAccessed(segment_uindex));
260+
}
261+
262+
// Either the segment is empty, or the first cell is not accessed. Set the first cell to
263+
// a value that is not a valid opcode (-1).
264+
if segment.is_empty() {
265+
segment.push(MemoryCell::NONE);
266+
}
267+
segment[0] = MemoryCell::new(MaybeRelocatable::Int(Felt252::from(-1)));
268+
Ok(())
269+
}
270+
240271
/// Retrieve a value from memory (either normal or temporary) and apply relocation rules
241272
pub(crate) fn get<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<Cow<'b, MaybeRelocatable>>
242273
where

0 commit comments

Comments
 (0)