Skip to content

Commit e3f4ccb

Browse files
feat: Field zero initialization (#1939)
Made a utility function that allocates and initializes a slice of memory with Rust's `alloc_zeroed`. Let me know if there are other places that could use this utility function
1 parent 22f1a5b commit e3f4ccb

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

crates/vm/src/system/memory/online/paged_vec.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use std::fmt::Debug;
22

33
use openvm_stark_backend::p3_maybe_rayon::prelude::*;
44

5+
use crate::utils::get_zeroed_array;
6+
57
#[derive(Debug, Clone)]
68
pub struct PagedVec<T> {
79
pages: Vec<Option<Box<[T]>>>,
@@ -37,8 +39,8 @@ impl<T: Copy + Default> PagedVec<T> {
3739
);
3840

3941
if self.pages[page_idx].is_none() {
40-
let page = vec![T::default(); self.page_size];
41-
self.pages[page_idx] = Some(page.into_boxed_slice());
42+
let page = get_zeroed_array(self.page_size);
43+
self.pages[page_idx] = Some(page);
4244
}
4345

4446
unsafe {
@@ -73,9 +75,9 @@ impl<T: Copy + Default> PagedVec<T> {
7375
*page.get_unchecked_mut(offset) = value;
7476
}
7577
} else {
76-
let mut page = vec![T::default(); self.page_size];
78+
let mut page = get_zeroed_array(self.page_size);
7779
page[offset] = value;
78-
self.pages[page_idx] = Some(page.into_boxed_slice());
80+
self.pages[page_idx] = Some(page);
7981
}
8082
}
8183

crates/vm/src/utils/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ mod stark_utils;
33
#[cfg(any(test, feature = "test-utils"))]
44
pub mod test_utils;
55

6+
use std::mem::size_of_val;
7+
68
pub use openvm_circuit_primitives::utils::next_power_of_two_or_zero;
79
use openvm_stark_backend::p3_field::PrimeField32;
810
#[cfg(any(test, feature = "test-utils"))]
@@ -55,3 +57,28 @@ pub unsafe fn slice_as_bytes<T>(slice: &[T]) -> &[u8] {
5557
// SAFETY: length and alignment are correct.
5658
unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const u8, len) }
5759
}
60+
61+
/// Allocates a boxed slice of `T` with all bytes zeroed.
62+
/// SAFETY: The caller must ensure that zero representation is valid for `T`.
63+
pub fn get_zeroed_array<T: Sized>(len: usize) -> Box<[T]> {
64+
if len == 0 {
65+
return Box::new([]);
66+
}
67+
68+
let layout = std::alloc::Layout::array::<T>(len).expect("Layout calculation failed");
69+
70+
// SAFETY: We're allocating memory and zero-initializing it directly.
71+
// This is safe because:
72+
// 1. T is Sized, so we know its exact size and alignment
73+
// 2. The caller guarantees that zero representation is valid for T
74+
// 3. We use the global allocator with the correct layout
75+
// 4. We only create the Box after successful allocation and initialization
76+
unsafe {
77+
let ptr = std::alloc::alloc_zeroed(layout) as *mut T;
78+
if ptr.is_null() {
79+
std::alloc::handle_alloc_error(layout);
80+
}
81+
let slice = std::slice::from_raw_parts_mut(ptr, len);
82+
Box::from_raw(slice)
83+
}
84+
}

0 commit comments

Comments
 (0)