Skip to content

Commit

Permalink
Add memory syscall helpers (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
febo authored Oct 1, 2024
1 parent ba375eb commit bdb9189
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 1 deletion.
3 changes: 2 additions & 1 deletion sdk/pinocchio/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! A library to build a Solana Program in Rust.
//! A library to build a Solana program in Rust.
//!
//! This library is intended to be used by on-chain programs only. It provides
//! a zero-dependency library to minimise dependencies conflits. For off-chain
Expand All @@ -14,6 +14,7 @@ pub mod account_info;
pub mod entrypoint;
pub mod instruction;
pub mod log;
pub mod memory;
pub mod program;
pub mod program_error;
pub mod pubkey;
Expand Down
137 changes: 137 additions & 0 deletions sdk/pinocchio/src/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//! Basic low-level memory operations.
//!
//! Within the SBF environment, these are implemented as syscalls and executed by
//! the runtime in native code.

#[cfg(target_os = "solana")]
use crate::syscalls;

/// Like C `memcpy`.
///
/// # Arguments
///
/// - `dst` - Destination
/// - `src` - Source
/// - `n` - Number of bytes to copy
///
/// # Errors
///
/// When executed within a SBF program, the memory regions spanning `n` bytes
/// from from the start of `dst` and `src` must be mapped program memory. If not,
/// the program will abort.
///
/// The memory regions spanning `n` bytes from `dst` and `src` from the start
/// of `dst` and `src` must not overlap. If they do, then the program will abort
/// or, if run outside of the SBF VM, will panic.
///
/// # Safety
///
/// This function does not verify that `n` is less than or equal to the
/// lengths of the `dst` and `src` slices passed to it — it will copy
/// bytes to and from beyond the slices.
///
/// Specifying an `n` greater than either the length of `dst` or `src` will
/// likely introduce undefined behavior.
#[inline]
pub unsafe fn sol_memcpy(dst: &mut [u8], src: &[u8], n: usize) {
#[cfg(target_os = "solana")]
syscalls::sol_memcpy_(dst.as_mut_ptr(), src.as_ptr(), n as u64);

#[cfg(not(target_os = "solana"))]
core::hint::black_box((dst, src, n));
}

/// Like C `memmove`.
///
/// # Arguments
///
/// - `dst` - Destination
/// - `src` - Source
/// - `n` - Number of bytes to copy
///
/// # Errors
///
/// When executed within a SBF program, the memory regions spanning `n` bytes
/// from from `dst` and `src` must be mapped program memory. If not, the program
/// will abort.
///
/// # Safety
///
/// The same safety rules apply as in [`ptr::copy`].
///
/// [`ptr::copy`]: https://doc.rust-lang.org/std/ptr/fn.copy.html
#[inline]
pub unsafe fn sol_memmove(dst: *mut u8, src: *mut u8, n: usize) {
#[cfg(target_os = "solana")]
syscalls::sol_memmove_(dst, src, n as u64);

#[cfg(not(target_os = "solana"))]
core::hint::black_box((dst, src, n));
}

/// Like C `memcmp`.
///
/// # Arguments
///
/// - `s1` - Slice to be compared
/// - `s2` - Slice to be compared
/// - `n` - Number of bytes to compare
///
/// # Errors
///
/// When executed within a SBF program, the memory regions spanning `n` bytes
/// from from the start of `dst` and `src` must be mapped program memory. If not,
/// the program will abort.
///
/// # Safety
///
/// It does not verify that `n` is less than or equal to the lengths of the
/// `dst` and `src` slices passed to it — it will read bytes beyond the
/// slices.
///
/// Specifying an `n` greater than either the length of `dst` or `src` will
/// likely introduce undefined behavior.
#[inline]
pub unsafe fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 {
#[allow(unused_mut)]
let mut result = 0;

#[cfg(target_os = "solana")]
syscalls::sol_memcmp_(s1.as_ptr(), s2.as_ptr(), n as u64, &mut result as *mut i32);

#[cfg(not(target_os = "solana"))]
core::hint::black_box((s1, s2, n, result));

result
}

/// Like C `memset`.
///
/// # Arguments
///
/// - `s` - Slice to be set
/// - `c` - Repeated byte to set
/// - `n` - Number of bytes to set
///
/// # Errors
///
/// When executed within a SBF program, the memory region spanning `n` bytes
/// from from the start of `s` must be mapped program memory. If not, the program
/// will abort.
///
/// # Safety
///
/// This function does not verify that `n` is less than or equal to the length
/// of the `s` slice passed to it — it will write bytes beyond the
/// slice.
///
/// Specifying an `n` greater than the length of `s` will likely introduce
/// undefined behavior.
#[inline]
pub unsafe fn sol_memset(s: &mut [u8], c: u8, n: usize) {
#[cfg(target_os = "solana")]
syscalls::sol_memset_(s.as_mut_ptr(), c, n as u64);

#[cfg(not(target_os = "solana"))]
core::hint::black_box((s, c, n));
}

0 comments on commit bdb9189

Please sign in to comment.