Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Add memory operation syscalls (backport #16447) (#18149)
Browse files Browse the repository at this point in the history
* Add memory operation syscalls (#16447)

(cherry picked from commit 2b50529)

# Conflicts:
#	programs/bpf/Cargo.lock
#	programs/bpf/rust/sysvar/tests/lib.rs
#	programs/bpf/tests/programs.rs
#	programs/bpf_loader/src/syscalls.rs
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
  • Loading branch information
mergify[bot] and jackcmay authored Jun 22, 2021
1 parent e259388 commit 57baf7f
Show file tree
Hide file tree
Showing 16 changed files with 877 additions and 180 deletions.
276 changes: 238 additions & 38 deletions programs/bpf/Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions programs/bpf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ members = [
"rust/many_args",
"rust/many_args_dep",
"rust/mem",
"rust/membuiltins",
"rust/noop",
"rust/panic",
"rust/param_passing",
Expand Down
1 change: 1 addition & 0 deletions programs/bpf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ fn main() {
"iter",
"many_args",
"mem",
"membuiltins",
"noop",
"panic",
"param_passing",
Expand Down
9 changes: 8 additions & 1 deletion programs/bpf/rust/mem/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-bpf-rust-mem"
edition = "2018"

[features]
no-entrypoint = []

[dependencies]
solana-program = { path = "../../../../sdk/program", version = "=1.6.15" }

[dev-dependencies]
solana-program-test = { path = "../../../../program-test", version = "=1.6.15" }
solana-sdk = { path = "../../../../sdk", version = "=1.6.15" }

[lib]
crate-type = ["cdylib"]
crate-type = ["cdylib", "lib"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
39 changes: 39 additions & 0 deletions programs/bpf/rust/mem/src/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! @brief Test mem functions
use crate::{run_mem_tests, MemOps};
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
program_memory::{sol_memcmp, sol_memcpy, sol_memmove, sol_memset},
pubkey::Pubkey,
};

entrypoint!(process_instruction);
#[allow(clippy::unnecessary_wraps)]
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
// Via syscalls
#[derive(Default)]
struct MemOpSyscalls();
impl MemOps for MemOpSyscalls {
fn memcpy(&self, dst: &mut [u8], src: &[u8], n: usize) {
sol_memcpy(dst, src, n)
}
unsafe fn memmove(&self, dst: *mut u8, src: *mut u8, n: usize) {
sol_memmove(dst, src, n)
}
fn memset(&self, s: &mut [u8], c: u8, n: usize) {
sol_memset(s, c, n)
}
fn memcmp(&self, s1: &[u8], s2: &[u8], n: usize) -> i32 {
sol_memcmp(s1, s2, n)
}
}
run_mem_tests(MemOpSyscalls::default());

Ok(())
}
245 changes: 110 additions & 135 deletions programs/bpf/rust/mem/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,190 +1,165 @@
//! @brief Test builtin mem functions
//! @brief Test mem functions
#![cfg(target_arch = "bpf")]
#![feature(rustc_private)]
#[cfg(not(feature = "no-entrypoint"))]
pub mod entrypoint;

extern crate compiler_builtins;
use solana_program::{custom_panic_default, entrypoint::SUCCESS};
pub trait MemOps {
fn memcpy(&self, dst: &mut [u8], src: &[u8], n: usize);
/// # Safety
unsafe fn memmove(&self, dst: *mut u8, src: *mut u8, n: usize);
fn memset(&self, s: &mut [u8], c: u8, n: usize);
fn memcmp(&self, s1: &[u8], s2: &[u8], n: usize) -> i32;
}

#[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
unsafe {
// memcpy
let src = &mut [1_u8; 18];
let dst = &mut [0_u8; 1];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 1);
assert_eq!(&src[..1], dst);
let dst = &mut [0_u8; 3];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 3);
assert_eq!(&src[..3], dst);
let dst = &mut [0_u8; 8];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 8);
assert_eq!(&src[..8], dst);
let dst = &mut [0_u8; 9];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 9);
assert_eq!(&src[..9], dst);
let dst = &mut [0_u8; 16];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 16);
assert_eq!(&src[..16], dst);
let dst = &mut [0_u8; 18];
compiler_builtins::mem::memcpy(&mut src[0] as *mut u8, &mut dst[0] as *mut u8, 18);
assert_eq!(&src[..18], dst);
let dst = &mut [0_u8; 18];
compiler_builtins::mem::memcpy(&mut src[1] as *mut u8, &mut dst[0] as *mut u8, 17);
assert_eq!(&src[1..], &dst[1..]);
let dst = &mut [0_u8; 18];
compiler_builtins::mem::memcpy(&mut src[1] as *mut u8, &mut dst[1] as *mut u8, 17);
assert_eq!(&src[1..], &dst[..17]);
pub fn run_mem_tests<T: MemOps>(mem_ops: T) {
// memcpy
let src = &[1_u8; 18];
let dst = &mut [0_u8; 1];
mem_ops.memcpy(dst, src, 1);
assert_eq!(&src[..1], dst);
let dst = &mut [0_u8; 3];
mem_ops.memcpy(dst, src, 3);
assert_eq!(&src[..3], dst);
let dst = &mut [0_u8; 8];
mem_ops.memcpy(dst, src, 8);
assert_eq!(&src[..8], dst);
let dst = &mut [0_u8; 9];
mem_ops.memcpy(dst, src, 9);
assert_eq!(&src[..9], dst);
let dst = &mut [0_u8; 16];
mem_ops.memcpy(dst, src, 16);
assert_eq!(&src[..16], dst);
let dst = &mut [0_u8; 18];
mem_ops.memcpy(dst, src, 18);
assert_eq!(&src[..18], dst);
let dst = &mut [0_u8; 18];
mem_ops.memcpy(dst, &src[1..], 17);
assert_eq!(&src[1..], &dst[..17]);
let dst = &mut [0_u8; 18];
mem_ops.memcpy(&mut dst[1..], &src[1..], 17);
assert_eq!(&src[1..], &dst[1..]);

// memmove
// memmove
unsafe {
let buf = &mut [1_u8, 0];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[1] as *mut u8, 1);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[1] as *mut u8, 1);
assert_eq!(buf[0], buf[1]);
let buf = &mut [1_u8, 0];
compiler_builtins::mem::memmove(&mut buf[1] as *mut u8, &mut buf[0] as *mut u8, 1);
mem_ops.memmove(&mut buf[1] as *mut u8, &mut buf[0] as *mut u8, 1);
assert_eq!(buf[0], buf[1]);
let buf = &mut [1_u8, 1, 1, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[3] as *mut u8, 3);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[3] as *mut u8, 3);
assert_eq!(buf[..3], buf[3..]);
let buf = &mut [1_u8, 1, 1, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[3] as *mut u8, &mut buf[0] as *mut u8, 3);
mem_ops.memmove(&mut buf[3] as *mut u8, &mut buf[0] as *mut u8, 3);
assert_eq!(buf[..3], buf[3..]);
let buf = &mut [1_u8, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[8] as *mut u8, 8);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[8] as *mut u8, 8);
assert_eq!(buf[..8], buf[8..]);
let buf = &mut [1_u8, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[8] as *mut u8, &mut buf[0] as *mut u8, 8);
mem_ops.memmove(&mut buf[8] as *mut u8, &mut buf[0] as *mut u8, 8);
assert_eq!(buf[..8], buf[8..]);
let buf = &mut [1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[9] as *mut u8, 9);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[9] as *mut u8, 9);
assert_eq!(buf[..9], buf[9..]);
let buf = &mut [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
compiler_builtins::mem::memmove(&mut buf[1] as *mut u8, &mut buf[0] as *mut u8, 9);
mem_ops.memmove(&mut buf[1] as *mut u8, &mut buf[0] as *mut u8, 9);
assert_eq!(&mut [0_u8, 0, 1, 2, 3, 4, 5, 6, 7, 8], buf);
let buf = &mut [1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0];
compiler_builtins::mem::memmove(&mut buf[9] as *mut u8, &mut buf[0] as *mut u8, 9);
mem_ops.memmove(&mut buf[9] as *mut u8, &mut buf[0] as *mut u8, 9);
assert_eq!(buf[..9], buf[9..]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[16] as *mut u8, 16);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[16] as *mut u8, 16);
assert_eq!(buf[..16], buf[16..]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[16] as *mut u8, &mut buf[0] as *mut u8, 16);
mem_ops.memmove(&mut buf[16] as *mut u8, &mut buf[0] as *mut u8, 16);
assert_eq!(buf[..16], buf[16..]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[0] as *mut u8, &mut buf[18] as *mut u8, 18);
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[18] as *mut u8, 18);
assert_eq!(buf[..18], buf[18..]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[18] as *mut u8, &mut buf[0] as *mut u8, 18);
mem_ops.memmove(&mut buf[18] as *mut u8, &mut buf[0] as *mut u8, 18);
assert_eq!(buf[..18], buf[18..]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[1] as *mut u8, &mut buf[18] as *mut u8, 17);
mem_ops.memmove(&mut buf[1] as *mut u8, &mut buf[18] as *mut u8, 17);
assert_eq!(buf[1..17], buf[18..34]);
let buf = &mut [
1_u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
compiler_builtins::mem::memmove(&mut buf[19] as *mut u8, &mut buf[1] as *mut u8, 17);
mem_ops.memmove(&mut buf[19] as *mut u8, &mut buf[1] as *mut u8, 17);
assert_eq!(buf[..17], buf[19..]);

// memset
let exp = &[1_u8; 18];
let buf = &mut [0_u8; 18];
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 1);
assert_eq!(exp[..1], buf[..1]);
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 3);
assert_eq!(exp[..3], buf[..3]);
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 8);
assert_eq!(exp[..8], buf[..8]);
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 9);
assert_eq!(exp[..9], buf[..9]);
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 16);
assert_eq!(exp[..16], buf[..16]);
compiler_builtins::mem::memset(&mut buf[0] as *mut u8, 1, 18);
assert_eq!(exp[..18], buf[..18]);
compiler_builtins::mem::memset(&mut buf[1] as *mut u8, 1, 17);
assert_eq!(exp[1..18], buf[1..18]);

// memcmp
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&[0_u8] as *const u8, &[1_u8] as *const u8, 1)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(
&[0_u8, 0, 0] as *const u8,
&[0_u8, 0, 1] as *const u8,
3
)
);
assert_eq!(
0,
compiler_builtins::mem::memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0] as *const u8,
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0] as *const u8,
9
)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0] as *const u8,
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 1] as *const u8,
9
)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0, 0] as *const u8,
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0, 1] as *const u8,
10
)
);
assert_eq!(
0,
compiler_builtins::mem::memcmp(&[0_u8; 8] as *const u8, &[0_u8; 8] as *const u8, 8)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&[0_u8; 8] as *const u8, &[1_u8; 8] as *const u8, 8)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&[0_u8; 16] as *const u8, &[1_u8; 16] as *const u8, 16)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&[0_u8; 18] as *const u8, &[1_u8; 18] as *const u8, 18)
);
let one = &[0_u8; 18];
let two = &[1_u8; 18];
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&one[1] as *const u8, &two[0] as *const u8, 17)
);
assert_eq!(
-1,
compiler_builtins::mem::memcmp(&one[1] as *const u8, &two[1] as *const u8, 17)
);
let buf = &mut [0_u8, 0, 0, 1, 1, 1, 1, 1, 0];
mem_ops.memmove(&mut buf[0] as *mut u8, &mut buf[3] as *mut u8, 5);
assert_eq!(buf, &mut [1, 1, 1, 1, 1, 1, 1, 1, 0]);
}

SUCCESS
}
// memset
let exp = &[1_u8; 18];
let buf = &mut [0_u8; 18];
mem_ops.memset(&mut buf[0..], 1, 1);
assert_eq!(exp[..1], buf[..1]);
mem_ops.memset(&mut buf[0..], 1, 3);
assert_eq!(exp[..3], buf[..3]);
mem_ops.memset(&mut buf[0..], 1, 8);
assert_eq!(exp[..8], buf[..8]);
mem_ops.memset(&mut buf[0..], 1, 9);
assert_eq!(exp[..9], buf[..9]);
mem_ops.memset(&mut buf[0..], 1, 16);
assert_eq!(exp[..16], buf[..16]);
mem_ops.memset(&mut buf[0..], 1, 18);
assert_eq!(exp[..18], buf[..18]);
mem_ops.memset(&mut buf[1..], 1, 17);
assert_eq!(exp[1..18], buf[1..18]);

custom_panic_default!();
// memcmp
assert_eq!(-1, mem_ops.memcmp(&[0_u8], &[1_u8], 1));
assert_eq!(-1, mem_ops.memcmp(&[0_u8, 0, 0], &[0_u8, 0, 1], 3));
assert_eq!(
0,
mem_ops.memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0],
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0],
9
)
);
assert_eq!(
-1,
mem_ops.memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0],
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 1],
9
)
);
assert_eq!(
-1,
mem_ops.memcmp(
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0, 0],
&[0_u8, 0, 0, 0, 0, 0, 0, 0, 0, 1],
10
)
);
assert_eq!(0, mem_ops.memcmp(&[0_u8; 8], &[0_u8; 8], 8));
assert_eq!(-1, mem_ops.memcmp(&[0_u8; 8], &[1_u8; 8], 8));
assert_eq!(-1, mem_ops.memcmp(&[0_u8; 16], &[1_u8; 16], 16));
assert_eq!(-1, mem_ops.memcmp(&[0_u8; 18], &[1_u8; 18], 18));
let one = &[0_u8; 18];
let two = &[1_u8; 18];
assert_eq!(-1, mem_ops.memcmp(&one[1..], &two[0..], 17));
assert_eq!(-1, mem_ops.memcmp(&one[1..], &two[1..], 17));
}
Loading

0 comments on commit 57baf7f

Please sign in to comment.