solana_bpf_loader_program/syscalls/
mem_ops.rs1use {super::*, crate::declare_syscall};
2
3fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), EbpfError> {
4 let compute_budget = invoke_context.get_compute_budget();
5 let cost = compute_budget
6 .mem_op_base_cost
7 .max(n.saturating_div(compute_budget.cpi_bytes_per_unit));
8 consume_compute_meter(invoke_context, cost)
9}
10
11declare_syscall!(
12 SyscallMemcpy,
14 fn inner_call(
15 invoke_context: &mut InvokeContext,
16 dst_addr: u64,
17 src_addr: u64,
18 n: u64,
19 _arg4: u64,
20 _arg5: u64,
21 memory_mapping: &mut MemoryMapping,
22 ) -> Result<u64, EbpfError> {
23 mem_op_consume(invoke_context, n)?;
24
25 if !is_nonoverlapping(src_addr, n, dst_addr, n) {
26 return Err(SyscallError::CopyOverlapping.into());
27 }
28
29 let dst_ptr = translate_slice_mut::<u8>(
30 memory_mapping,
31 dst_addr,
32 n,
33 invoke_context.get_check_aligned(),
34 invoke_context.get_check_size(),
35 )?
36 .as_mut_ptr();
37 let src_ptr = translate_slice::<u8>(
38 memory_mapping,
39 src_addr,
40 n,
41 invoke_context.get_check_aligned(),
42 invoke_context.get_check_size(),
43 )?
44 .as_ptr();
45 if !is_nonoverlapping(src_ptr as usize, n as usize, dst_ptr as usize, n as usize) {
46 unsafe {
47 std::ptr::copy(src_ptr, dst_ptr, n as usize);
48 }
49 } else {
50 unsafe {
51 std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, n as usize);
52 }
53 }
54 Ok(0)
55 }
56);
57
58declare_syscall!(
59 SyscallMemmove,
61 fn inner_call(
62 invoke_context: &mut InvokeContext,
63 dst_addr: u64,
64 src_addr: u64,
65 n: u64,
66 _arg4: u64,
67 _arg5: u64,
68 memory_mapping: &mut MemoryMapping,
69 ) -> Result<u64, EbpfError> {
70 mem_op_consume(invoke_context, n)?;
71
72 let dst = translate_slice_mut::<u8>(
73 memory_mapping,
74 dst_addr,
75 n,
76 invoke_context.get_check_aligned(),
77 invoke_context.get_check_size(),
78 )?;
79 let src = translate_slice::<u8>(
80 memory_mapping,
81 src_addr,
82 n,
83 invoke_context.get_check_aligned(),
84 invoke_context.get_check_size(),
85 )?;
86 unsafe {
87 std::ptr::copy(src.as_ptr(), dst.as_mut_ptr(), n as usize);
88 }
89 Ok(0)
90 }
91);
92
93declare_syscall!(
94 SyscallMemcmp,
96 fn inner_call(
97 invoke_context: &mut InvokeContext,
98 s1_addr: u64,
99 s2_addr: u64,
100 n: u64,
101 cmp_result_addr: u64,
102 _arg5: u64,
103 memory_mapping: &mut MemoryMapping,
104 ) -> Result<u64, EbpfError> {
105 mem_op_consume(invoke_context, n)?;
106
107 let s1 = translate_slice::<u8>(
108 memory_mapping,
109 s1_addr,
110 n,
111 invoke_context.get_check_aligned(),
112 invoke_context.get_check_size(),
113 )?;
114 let s2 = translate_slice::<u8>(
115 memory_mapping,
116 s2_addr,
117 n,
118 invoke_context.get_check_aligned(),
119 invoke_context.get_check_size(),
120 )?;
121 let cmp_result = translate_type_mut::<i32>(
122 memory_mapping,
123 cmp_result_addr,
124 invoke_context.get_check_aligned(),
125 )?;
126 let mut i = 0;
127 while i < n as usize {
128 let a = *s1.get(i).ok_or(SyscallError::InvalidLength)?;
129 let b = *s2.get(i).ok_or(SyscallError::InvalidLength)?;
130 if a != b {
131 *cmp_result = (a as i32).saturating_sub(b as i32);
132 return Ok(0);
133 };
134 i = i.saturating_add(1);
135 }
136 *cmp_result = 0;
137 Ok(0)
138 }
139);
140
141declare_syscall!(
142 SyscallMemset,
144 fn inner_call(
145 invoke_context: &mut InvokeContext,
146 s_addr: u64,
147 c: u64,
148 n: u64,
149 _arg4: u64,
150 _arg5: u64,
151 memory_mapping: &mut MemoryMapping,
152 ) -> Result<u64, EbpfError> {
153 mem_op_consume(invoke_context, n)?;
154
155 let s = translate_slice_mut::<u8>(
156 memory_mapping,
157 s_addr,
158 n,
159 invoke_context.get_check_aligned(),
160 invoke_context.get_check_size(),
161 )?;
162 for val in s.iter_mut().take(n as usize) {
163 *val = c as u8;
164 }
165 Ok(0)
166 }
167);