1use {
4 solana_sbpf::memory_region::{AccessType, MemoryMapping},
5 solana_transaction_context::vm_slice::VmSlice,
6 std::mem::align_of,
7};
8
9#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
11pub enum MemoryTranslationError {
12 #[error("Unaligned pointer")]
13 UnalignedPointer,
14 #[error("InvalidLength")]
15 InvalidLength,
16}
17
18pub fn address_is_aligned<T>(address: u64) -> bool {
19 (address as *mut T as usize)
20 .checked_rem(align_of::<T>())
21 .map(|rem| rem == 0)
22 .expect("T to be non-zero aligned")
23}
24
25#[macro_export]
27macro_rules! translate_inner {
28 ($memory_mapping:expr, $map:ident, $access_type:expr, $vm_addr:expr, $len:expr $(,)?) => {
29 Result::<u64, Box<dyn std::error::Error>>::from(
30 $memory_mapping
31 .$map($access_type, $vm_addr, $len)
32 .map_err(|err| err.into()),
33 )
34 };
35}
36
37#[macro_export]
39macro_rules! translate_type_inner {
40 ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $T:ty, $check_aligned:expr $(,)?) => {{
41 let host_addr = $crate::translate_inner!(
42 $memory_mapping,
43 map,
44 $access_type,
45 $vm_addr,
46 size_of::<$T>() as u64
47 )?;
48 if !$check_aligned {
49 Ok(unsafe { std::mem::transmute::<u64, &mut $T>(host_addr) })
50 } else if !$crate::memory::address_is_aligned::<$T>(host_addr) {
51 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
52 } else {
53 Ok(unsafe { &mut *(host_addr as *mut $T) })
54 }
55 }};
56}
57
58#[macro_export]
60macro_rules! translate_slice_inner {
61 ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $len:expr, $T:ty, $check_aligned:expr $(,)?) => {{
62 if $len == 0 {
63 Ok(std::ptr::slice_from_raw_parts_mut(
64 std::ptr::dangling_mut::<$T>(),
65 0,
66 ))
67 } else {
68 let total_size = $len.saturating_mul(size_of::<$T>() as u64);
69 if isize::try_from(total_size).is_err() {
70 Err($crate::memory::MemoryTranslationError::InvalidLength.into())
71 } else {
72 match $crate::translate_inner!(
73 $memory_mapping,
74 map,
75 $access_type,
76 $vm_addr,
77 total_size
78 ) {
79 Err(e) => Err(e),
80 Ok(host_addr)
81 if $check_aligned
82 && !$crate::memory::address_is_aligned::<$T>(host_addr) =>
83 {
84 Err($crate::memory::MemoryTranslationError::UnalignedPointer.into())
85 }
86 Ok(host_addr) => Ok(std::ptr::slice_from_raw_parts_mut(
87 host_addr as *mut $T,
88 $len as usize,
89 )),
90 }
91 }
92 }
93 }};
94}
95
96pub fn translate_type<'a, T>(
97 memory_mapping: &MemoryMapping,
98 vm_addr: u64,
99 check_aligned: bool,
100) -> Result<&'a T, Box<dyn std::error::Error>> {
101 translate_type_inner!(memory_mapping, AccessType::Load, vm_addr, T, check_aligned)
102 .map(|value| &*value)
103}
104
105pub fn translate_slice<T>(
106 memory_mapping: &MemoryMapping,
107 vm_addr: u64,
108 len: u64,
109 check_aligned: bool,
110) -> Result<&[T], Box<dyn std::error::Error>> {
111 translate_slice_inner!(
112 memory_mapping,
113 AccessType::Load,
114 vm_addr,
115 len,
116 T,
117 check_aligned,
118 )
119 .map(|value| unsafe {
120 &*value
124 })
125}
126
127pub fn translate_type_mut_for_cpi<'a, T>(
130 memory_mapping: &MemoryMapping,
131 vm_addr: u64,
132 check_aligned: bool,
133) -> Result<&'a mut T, Box<dyn std::error::Error>> {
134 translate_type_inner!(memory_mapping, AccessType::Store, vm_addr, T, check_aligned)
135}
136
137pub unsafe fn translate_slice_mut_for_cpi<'a, T>(
147 memory_mapping: &MemoryMapping,
148 vm_addr: u64,
149 len: u64,
150 check_aligned: bool,
151) -> Result<&'a mut [T], Box<dyn std::error::Error>> {
152 translate_slice_inner!(
153 memory_mapping,
154 AccessType::Store,
155 vm_addr,
156 len,
157 T,
158 check_aligned,
159 )
160 .map(|p| unsafe {
161 &mut *p
163 })
164}
165
166pub fn translate_vm_slice<'a, T>(
167 slice: &VmSlice<T>,
168 memory_mapping: &'a MemoryMapping,
169 check_aligned: bool,
170) -> Result<&'a [T], Box<dyn std::error::Error>> {
171 translate_slice::<T>(memory_mapping, slice.ptr(), slice.len(), check_aligned)
172}