1use {solana_sbpf::memory_region::MemoryMapping, solana_transaction_context::vm_slice::VmSlice};
4
5#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
7pub enum MemoryTranslationError {
8 #[error("Unaligned pointer")]
9 UnalignedPointer,
10 #[error("InvalidLength")]
11 InvalidLength,
12}
13
14#[macro_export]
16macro_rules! translate_inner {
17 ($memory_mapping:expr, $map:ident, $access_type:expr, $vm_addr:expr, $len:expr $(,)?) => {
18 Result::<$crate::solana_sbpf::memory_region::HostBuffer, Box<dyn std::error::Error>>::from(
19 $memory_mapping
20 .$map($access_type, $vm_addr, $len)
21 .map_err(|err| err.into()),
22 )
23 };
24}
25
26#[macro_export]
28macro_rules! translate_type_inner {
29 ($memory_mapping:expr, AccessType::Store, $vm_addr:expr, $T:ty, $check_aligned:expr $(,)?) => {{
30 let host_addr = $crate::translate_inner!(
31 $memory_mapping,
32 map,
33 $crate::solana_sbpf::memory_region::AccessType::Store,
34 $vm_addr,
35 size_of::<$T>() as u64
36 )?;
37 let ptr = host_addr.ptr_mut().cast::<$T>();
38 if $check_aligned && !ptr.is_aligned() {
39 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
40 } else {
41 Ok(unsafe { ptr.as_mut_unchecked() })
42 }
43 }};
44 ($memory_mapping:expr, AccessType::Load, $vm_addr:expr, $T:ty, $check_aligned:expr $(,)?) => {{
45 let host_addr = $crate::translate_inner!(
46 $memory_mapping,
47 map,
48 $crate::solana_sbpf::memory_region::AccessType::Load,
49 $vm_addr,
50 size_of::<$T>() as u64
51 )?;
52 let ptr = host_addr.ptr().cast::<$T>();
53 if $check_aligned && !ptr.is_aligned() {
54 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
55 } else {
56 Ok(unsafe { ptr.as_ref_unchecked() })
57 }
58 }};
59}
60
61#[macro_export]
63macro_rules! translate_slice_inner {
64 ($memory_mapping:expr, AccessType::Store, $vm_addr:expr, $len:expr, $T:ty, $check_aligned:expr $(,)?) => {{
65 if $len == 0 {
66 Ok(std::ptr::slice_from_raw_parts_mut(
67 std::ptr::dangling_mut::<$T>(),
68 0,
69 ))
70 } else {
71 let total_size = $len.saturating_mul(size_of::<$T>() as u64);
72 if isize::try_from(total_size).is_err() {
73 Err($crate::memory::MemoryTranslationError::InvalidLength.into())
74 } else {
75 match $crate::translate_inner!(
76 $memory_mapping,
77 map,
78 $crate::solana_sbpf::memory_region::AccessType::Store,
79 $vm_addr,
80 total_size
81 ) {
82 Err(e) => Err(e),
83 Ok(host_buf) if $check_aligned && !host_buf.ptr().cast::<$T>().is_aligned() => {
84 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
85 }
86 Ok(host_buf) => Ok(std::ptr::slice_from_raw_parts_mut(
87 host_buf.ptr_mut().cast(),
88 $len as usize,
89 )),
90 }
91 }
92 }
93 }};
94 ($memory_mapping:expr, AccessType::Load, $vm_addr:expr, $len:expr, $T:ty, $check_aligned:expr $(,)?) => {{
95 if $len == 0 {
96 Ok(std::ptr::slice_from_raw_parts(
97 std::ptr::dangling_mut::<$T>(),
98 0,
99 ))
100 } else {
101 let total_size = $len.saturating_mul(size_of::<$T>() as u64);
102 if isize::try_from(total_size).is_err() {
103 Err($crate::memory::MemoryTranslationError::InvalidLength.into())
104 } else {
105 match $crate::translate_inner!(
106 $memory_mapping,
107 map,
108 $crate::solana_sbpf::memory_region::AccessType::Load,
109 $vm_addr,
110 total_size
111 ) {
112 Err(e) => Err(e),
113 Ok(host_buf) if $check_aligned && !host_buf.ptr().cast::<$T>().is_aligned() => {
114 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
115 }
116 Ok(host_buf) => Ok(std::ptr::slice_from_raw_parts(
117 host_buf.ptr().cast(),
118 $len as usize,
119 )),
120 }
121 }
122 }
123 }};
124}
125
126pub fn translate_type<'a, T>(
127 memory_mapping: &MemoryMapping,
128 vm_addr: u64,
129 check_aligned: bool,
130) -> Result<&'a T, Box<dyn std::error::Error>> {
131 translate_type_inner!(memory_mapping, AccessType::Load, vm_addr, T, check_aligned)
132}
133
134pub fn translate_slice<T>(
135 memory_mapping: &MemoryMapping,
136 vm_addr: u64,
137 len: u64,
138 check_aligned: bool,
139) -> Result<&[T], Box<dyn std::error::Error>> {
140 translate_slice_inner!(
141 memory_mapping,
142 AccessType::Load,
143 vm_addr,
144 len,
145 T,
146 check_aligned,
147 )
148 .map(|value| unsafe {
149 &*value
153 })
154}
155
156pub fn translate_type_mut_for_cpi<'a, T>(
159 memory_mapping: &MemoryMapping,
160 vm_addr: u64,
161 check_aligned: bool,
162) -> Result<&'a mut T, Box<dyn std::error::Error>> {
163 translate_type_inner!(memory_mapping, AccessType::Store, vm_addr, T, check_aligned)
164}
165
166pub unsafe fn translate_slice_mut_for_cpi<'a, T>(
176 memory_mapping: &MemoryMapping,
177 vm_addr: u64,
178 len: u64,
179 check_aligned: bool,
180) -> Result<&'a mut [T], Box<dyn std::error::Error>> {
181 translate_slice_inner!(
182 memory_mapping,
183 AccessType::Store,
184 vm_addr,
185 len,
186 T,
187 check_aligned,
188 )
189 .map(|p| unsafe {
190 &mut *p
192 })
193}
194
195pub fn translate_vm_slice<'a, T>(
196 slice: &VmSlice<T>,
197 memory_mapping: &'a MemoryMapping,
198 check_aligned: bool,
199) -> Result<&'a [T], Box<dyn std::error::Error>> {
200 translate_slice::<T>(memory_mapping, slice.ptr(), slice.len(), check_aligned)
201}