solana/programs/bpf_loader/src/syscalls/mem_ops.rs

168 lines
4.4 KiB
Rust

use {super::*, crate::declare_syscall};
fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Error> {
let compute_budget = invoke_context.get_compute_budget();
let cost = compute_budget
.mem_op_base_cost
.max(n.saturating_div(compute_budget.cpi_bytes_per_unit));
consume_compute_meter(invoke_context, cost)
}
declare_syscall!(
/// memcpy
SyscallMemcpy,
fn inner_call(
invoke_context: &mut InvokeContext,
dst_addr: u64,
src_addr: u64,
n: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
if !is_nonoverlapping(src_addr, n, dst_addr, n) {
return Err(SyscallError::CopyOverlapping.into());
}
let dst_ptr = translate_slice_mut::<u8>(
memory_mapping,
dst_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?
.as_mut_ptr();
let src_ptr = translate_slice::<u8>(
memory_mapping,
src_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?
.as_ptr();
if !is_nonoverlapping(src_ptr as usize, n as usize, dst_ptr as usize, n as usize) {
unsafe {
std::ptr::copy(src_ptr, dst_ptr, n as usize);
}
} else {
unsafe {
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, n as usize);
}
}
Ok(0)
}
);
declare_syscall!(
/// memmove
SyscallMemmove,
fn inner_call(
invoke_context: &mut InvokeContext,
dst_addr: u64,
src_addr: u64,
n: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let dst = translate_slice_mut::<u8>(
memory_mapping,
dst_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let src = translate_slice::<u8>(
memory_mapping,
src_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
unsafe {
std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize);
}
Ok(0)
}
);
declare_syscall!(
/// memcmp
SyscallMemcmp,
fn inner_call(
invoke_context: &mut InvokeContext,
s1_addr: u64,
s2_addr: u64,
n: u64,
cmp_result_addr: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let s1 = translate_slice::<u8>(
memory_mapping,
s1_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let s2 = translate_slice::<u8>(
memory_mapping,
s2_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
let cmp_result = translate_type_mut::<i32>(
memory_mapping,
cmp_result_addr,
invoke_context.get_check_aligned(),
)?;
let mut i = 0;
while i < n as usize {
let a = *s1.get(i).ok_or(SyscallError::InvalidLength)?;
let b = *s2.get(i).ok_or(SyscallError::InvalidLength)?;
if a != b {
*cmp_result = (a as i32).saturating_sub(b as i32);
return Ok(0);
};
i = i.saturating_add(1);
}
*cmp_result = 0;
Ok(0)
}
);
declare_syscall!(
/// memset
SyscallMemset,
fn inner_call(
invoke_context: &mut InvokeContext,
s_addr: u64,
c: u64,
n: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Error> {
mem_op_consume(invoke_context, n)?;
let s = translate_slice_mut::<u8>(
memory_mapping,
s_addr,
n,
invoke_context.get_check_aligned(),
invoke_context.get_check_size(),
)?;
for val in s.iter_mut().take(n as usize) {
*val = c as u8;
}
Ok(0)
}
);