Skip to content

Commit bdb9189

Browse files
authored
Add memory syscall helpers (#20)
1 parent ba375eb commit bdb9189

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed

sdk/pinocchio/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! A library to build a Solana Program in Rust.
1+
//! A library to build a Solana program in Rust.
22
//!
33
//! This library is intended to be used by on-chain programs only. It provides
44
//! a zero-dependency library to minimise dependencies conflits. For off-chain
@@ -14,6 +14,7 @@ pub mod account_info;
1414
pub mod entrypoint;
1515
pub mod instruction;
1616
pub mod log;
17+
pub mod memory;
1718
pub mod program;
1819
pub mod program_error;
1920
pub mod pubkey;

sdk/pinocchio/src/memory.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Basic low-level memory operations.
2+
//!
3+
//! Within the SBF environment, these are implemented as syscalls and executed by
4+
//! the runtime in native code.
5+
6+
#[cfg(target_os = "solana")]
7+
use crate::syscalls;
8+
9+
/// Like C `memcpy`.
10+
///
11+
/// # Arguments
12+
///
13+
/// - `dst` - Destination
14+
/// - `src` - Source
15+
/// - `n` - Number of bytes to copy
16+
///
17+
/// # Errors
18+
///
19+
/// When executed within a SBF program, the memory regions spanning `n` bytes
20+
/// from from the start of `dst` and `src` must be mapped program memory. If not,
21+
/// the program will abort.
22+
///
23+
/// The memory regions spanning `n` bytes from `dst` and `src` from the start
24+
/// of `dst` and `src` must not overlap. If they do, then the program will abort
25+
/// or, if run outside of the SBF VM, will panic.
26+
///
27+
/// # Safety
28+
///
29+
/// This function does not verify that `n` is less than or equal to the
30+
/// lengths of the `dst` and `src` slices passed to it — it will copy
31+
/// bytes to and from beyond the slices.
32+
///
33+
/// Specifying an `n` greater than either the length of `dst` or `src` will
34+
/// likely introduce undefined behavior.
35+
#[inline]
36+
pub unsafe fn sol_memcpy(dst: &mut [u8], src: &[u8], n: usize) {
37+
#[cfg(target_os = "solana")]
38+
syscalls::sol_memcpy_(dst.as_mut_ptr(), src.as_ptr(), n as u64);
39+
40+
#[cfg(not(target_os = "solana"))]
41+
core::hint::black_box((dst, src, n));
42+
}
43+
44+
/// Like C `memmove`.
45+
///
46+
/// # Arguments
47+
///
48+
/// - `dst` - Destination
49+
/// - `src` - Source
50+
/// - `n` - Number of bytes to copy
51+
///
52+
/// # Errors
53+
///
54+
/// When executed within a SBF program, the memory regions spanning `n` bytes
55+
/// from from `dst` and `src` must be mapped program memory. If not, the program
56+
/// will abort.
57+
///
58+
/// # Safety
59+
///
60+
/// The same safety rules apply as in [`ptr::copy`].
61+
///
62+
/// [`ptr::copy`]: https://doc.rust-lang.org/std/ptr/fn.copy.html
63+
#[inline]
64+
pub unsafe fn sol_memmove(dst: *mut u8, src: *mut u8, n: usize) {
65+
#[cfg(target_os = "solana")]
66+
syscalls::sol_memmove_(dst, src, n as u64);
67+
68+
#[cfg(not(target_os = "solana"))]
69+
core::hint::black_box((dst, src, n));
70+
}
71+
72+
/// Like C `memcmp`.
73+
///
74+
/// # Arguments
75+
///
76+
/// - `s1` - Slice to be compared
77+
/// - `s2` - Slice to be compared
78+
/// - `n` - Number of bytes to compare
79+
///
80+
/// # Errors
81+
///
82+
/// When executed within a SBF program, the memory regions spanning `n` bytes
83+
/// from from the start of `dst` and `src` must be mapped program memory. If not,
84+
/// the program will abort.
85+
///
86+
/// # Safety
87+
///
88+
/// It does not verify that `n` is less than or equal to the lengths of the
89+
/// `dst` and `src` slices passed to it — it will read bytes beyond the
90+
/// slices.
91+
///
92+
/// Specifying an `n` greater than either the length of `dst` or `src` will
93+
/// likely introduce undefined behavior.
94+
#[inline]
95+
pub unsafe fn sol_memcmp(s1: &[u8], s2: &[u8], n: usize) -> i32 {
96+
#[allow(unused_mut)]
97+
let mut result = 0;
98+
99+
#[cfg(target_os = "solana")]
100+
syscalls::sol_memcmp_(s1.as_ptr(), s2.as_ptr(), n as u64, &mut result as *mut i32);
101+
102+
#[cfg(not(target_os = "solana"))]
103+
core::hint::black_box((s1, s2, n, result));
104+
105+
result
106+
}
107+
108+
/// Like C `memset`.
109+
///
110+
/// # Arguments
111+
///
112+
/// - `s` - Slice to be set
113+
/// - `c` - Repeated byte to set
114+
/// - `n` - Number of bytes to set
115+
///
116+
/// # Errors
117+
///
118+
/// When executed within a SBF program, the memory region spanning `n` bytes
119+
/// from from the start of `s` must be mapped program memory. If not, the program
120+
/// will abort.
121+
///
122+
/// # Safety
123+
///
124+
/// This function does not verify that `n` is less than or equal to the length
125+
/// of the `s` slice passed to it — it will write bytes beyond the
126+
/// slice.
127+
///
128+
/// Specifying an `n` greater than the length of `s` will likely introduce
129+
/// undefined behavior.
130+
#[inline]
131+
pub unsafe fn sol_memset(s: &mut [u8], c: u8, n: usize) {
132+
#[cfg(target_os = "solana")]
133+
syscalls::sol_memset_(s.as_mut_ptr(), c, n as u64);
134+
135+
#[cfg(not(target_os = "solana"))]
136+
core::hint::black_box((s, c, n));
137+
}

0 commit comments

Comments
 (0)