solana_bpf_loader_program/syscalls/
mem_ops.rs

1use {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    /// memcpy
13    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    /// memmove
60    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    /// memcmp
95    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    /// memset
143    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);