1use crate::{
22 runtime::RunFallibleError, BackendExternalities, BackendSyscallError, TrapExplanation,
23 UndefinedTerminationReason, UnrecoverableMemoryError,
24};
25use alloc::vec::Vec;
26use core::{
27 fmt::Debug,
28 marker::PhantomData,
29 mem,
30 mem::{size_of, MaybeUninit},
31 result::Result,
32 slice,
33};
34use gear_core::{
35 buffer::{RuntimeBuffer, RuntimeBufferSizeError},
36 memory::{Memory, MemoryError, MemoryInterval},
37};
38use gear_core_errors::MemoryError as FallibleMemoryError;
39use num_enum::{IntoPrimitive, TryFromPrimitive};
40use scale_info::scale::{Decode, DecodeAll, MaxEncodedLen};
41
42#[derive(Debug, Clone, IntoPrimitive, TryFromPrimitive)]
45#[repr(u8)]
46pub enum ProcessAccessError {
47 OutOfBounds = 1,
48 GasLimitExceeded = 2,
49}
50
51#[derive(Debug, Clone, derive_more::From)]
52pub enum MemoryAccessError {
53 Memory(MemoryError),
54 ProcessAccess(ProcessAccessError),
55 RuntimeBuffer(RuntimeBufferSizeError),
56 Decode,
58}
59
60impl BackendSyscallError for MemoryAccessError {
61 fn into_termination_reason(self) -> UndefinedTerminationReason {
62 match self {
63 MemoryAccessError::ProcessAccess(ProcessAccessError::OutOfBounds)
64 | MemoryAccessError::Memory(MemoryError::AccessOutOfBounds) => {
65 TrapExplanation::UnrecoverableExt(
66 UnrecoverableMemoryError::AccessOutOfBounds.into(),
67 )
68 .into()
69 }
70 MemoryAccessError::RuntimeBuffer(RuntimeBufferSizeError) => {
71 TrapExplanation::UnrecoverableExt(
72 UnrecoverableMemoryError::RuntimeAllocOutOfBounds.into(),
73 )
74 .into()
75 }
76 MemoryAccessError::ProcessAccess(ProcessAccessError::GasLimitExceeded) => {
81 UndefinedTerminationReason::ProcessAccessErrorResourcesExceed
82 }
83 MemoryAccessError::Decode => unreachable!(),
84 }
85 }
86
87 fn into_run_fallible_error(self) -> RunFallibleError {
88 match self {
89 MemoryAccessError::Memory(MemoryError::AccessOutOfBounds)
90 | MemoryAccessError::ProcessAccess(ProcessAccessError::OutOfBounds) => {
91 RunFallibleError::FallibleExt(FallibleMemoryError::AccessOutOfBounds.into())
92 }
93 MemoryAccessError::RuntimeBuffer(RuntimeBufferSizeError) => {
94 RunFallibleError::FallibleExt(FallibleMemoryError::RuntimeAllocOutOfBounds.into())
95 }
96 e => RunFallibleError::UndefinedTerminationReason(e.into_termination_reason()),
97 }
98 }
99}
100
101pub trait MemoryAccessRecorder {
103 fn register_read(&mut self, ptr: u32, size: u32) -> WasmMemoryRead;
105
106 fn register_read_as<T: Sized>(&mut self, ptr: u32) -> WasmMemoryReadAs<T>;
108
109 fn register_read_decoded<T: Decode + MaxEncodedLen>(
111 &mut self,
112 ptr: u32,
113 ) -> WasmMemoryReadDecoded<T>;
114
115 fn register_write(&mut self, ptr: u32, size: u32) -> WasmMemoryWrite;
117
118 fn register_write_as<T: Sized>(&mut self, ptr: u32) -> WasmMemoryWriteAs<T>;
120}
121
122pub trait MemoryOwner {
123 fn read(&mut self, read: WasmMemoryRead) -> Result<Vec<u8>, MemoryAccessError>;
125
126 fn read_as<T: Sized>(&mut self, read: WasmMemoryReadAs<T>) -> Result<T, MemoryAccessError>;
128
129 fn read_decoded<T: Decode + MaxEncodedLen>(
131 &mut self,
132 read: WasmMemoryReadDecoded<T>,
133 ) -> Result<T, MemoryAccessError>;
134
135 fn write(&mut self, write: WasmMemoryWrite, buff: &[u8]) -> Result<(), MemoryAccessError>;
137
138 fn write_as<T: Sized>(
140 &mut self,
141 write: WasmMemoryWriteAs<T>,
142 obj: T,
143 ) -> Result<(), MemoryAccessError>;
144}
145
146#[derive(Debug)]
163pub struct MemoryAccessManager<Ext> {
164 pub(crate) reads: Vec<MemoryInterval>,
166 pub(crate) writes: Vec<MemoryInterval>,
167 pub(crate) _phantom: PhantomData<Ext>,
168}
169
170impl<Ext> Default for MemoryAccessManager<Ext> {
171 fn default() -> Self {
172 Self {
173 reads: Vec::new(),
174 writes: Vec::new(),
175 _phantom: PhantomData,
176 }
177 }
178}
179
180impl<Ext> MemoryAccessRecorder for MemoryAccessManager<Ext> {
181 fn register_read(&mut self, ptr: u32, size: u32) -> WasmMemoryRead {
182 if size > 0 {
183 self.reads.push(MemoryInterval { offset: ptr, size });
184 }
185 WasmMemoryRead { ptr, size }
186 }
187
188 fn register_read_as<T: Sized>(&mut self, ptr: u32) -> WasmMemoryReadAs<T> {
189 let size = size_of::<T>() as u32;
190 if size > 0 {
191 self.reads.push(MemoryInterval { offset: ptr, size });
192 }
193 WasmMemoryReadAs {
194 ptr,
195 _phantom: PhantomData,
196 }
197 }
198
199 fn register_read_decoded<T: Decode + MaxEncodedLen>(
200 &mut self,
201 ptr: u32,
202 ) -> WasmMemoryReadDecoded<T> {
203 let size = T::max_encoded_len() as u32;
204 if size > 0 {
205 self.reads.push(MemoryInterval { offset: ptr, size });
206 }
207 WasmMemoryReadDecoded {
208 ptr,
209 _phantom: PhantomData,
210 }
211 }
212
213 fn register_write(&mut self, ptr: u32, size: u32) -> WasmMemoryWrite {
214 if size > 0 {
215 self.writes.push(MemoryInterval { offset: ptr, size });
216 }
217 WasmMemoryWrite { ptr, size }
218 }
219
220 fn register_write_as<T: Sized>(&mut self, ptr: u32) -> WasmMemoryWriteAs<T> {
221 let size = size_of::<T>() as u32;
222 if size > 0 {
223 self.writes.push(MemoryInterval { offset: ptr, size });
224 }
225 WasmMemoryWriteAs {
226 ptr,
227 _phantom: PhantomData,
228 }
229 }
230}
231
232impl<Ext: BackendExternalities> MemoryAccessManager<Ext> {
233 pub(crate) fn pre_process_memory_accesses(
235 &mut self,
236 gas_counter: &mut u64,
237 ) -> Result<(), MemoryAccessError> {
238 if self.reads.is_empty() && self.writes.is_empty() {
239 return Ok(());
240 }
241
242 let res = Ext::pre_process_memory_accesses(&self.reads, &self.writes, gas_counter);
243
244 self.reads.clear();
245 self.writes.clear();
246
247 res.map_err(Into::into)
248 }
249
250 fn read_into_buf<M: Memory>(
252 &mut self,
253 memory: &M,
254 ptr: u32,
255 buff: &mut [u8],
256 gas_counter: &mut u64,
257 ) -> Result<(), MemoryAccessError> {
258 self.pre_process_memory_accesses(gas_counter)?;
259 memory.read(ptr, buff).map_err(Into::into)
260 }
261
262 pub fn read<M: Memory>(
264 &mut self,
265 memory: &M,
266 read: WasmMemoryRead,
267 gas_counter: &mut u64,
268 ) -> Result<Vec<u8>, MemoryAccessError> {
269 let buff = if read.size == 0 {
270 Vec::new()
271 } else {
272 let mut buff = RuntimeBuffer::try_new_default(read.size as usize)?.into_vec();
273 self.read_into_buf(memory, read.ptr, &mut buff, gas_counter)?;
274 buff
275 };
276 Ok(buff)
277 }
278
279 pub fn read_decoded<M: Memory, T: Decode + MaxEncodedLen>(
281 &mut self,
282 memory: &M,
283 read: WasmMemoryReadDecoded<T>,
284 gas_counter: &mut u64,
285 ) -> Result<T, MemoryAccessError> {
286 let size = T::max_encoded_len();
287 let buff = if size == 0 {
288 Vec::new()
289 } else {
290 let mut buff = RuntimeBuffer::try_new_default(size)?.into_vec();
291 self.read_into_buf(memory, read.ptr, &mut buff, gas_counter)?;
292 buff
293 };
294 let decoded = T::decode_all(&mut &buff[..]).map_err(|_| MemoryAccessError::Decode)?;
295 Ok(decoded)
296 }
297
298 pub fn read_as<M: Memory, T: Sized>(
300 &mut self,
301 memory: &M,
302 read: WasmMemoryReadAs<T>,
303 gas_counter: &mut u64,
304 ) -> Result<T, MemoryAccessError> {
305 self.pre_process_memory_accesses(gas_counter)?;
306 read_memory_as(memory, read.ptr).map_err(Into::into)
307 }
308
309 pub fn write<M: Memory>(
311 &mut self,
312 memory: &mut M,
313 write: WasmMemoryWrite,
314 buff: &[u8],
315 gas_counter: &mut u64,
316 ) -> Result<(), MemoryAccessError> {
317 if buff.len() != write.size as usize {
318 unreachable!("Backend bug error: buffer size is not equal to registered buffer size");
319 }
320 if write.size == 0 {
321 Ok(())
322 } else {
323 self.pre_process_memory_accesses(gas_counter)?;
324 memory.write(write.ptr, buff).map_err(Into::into)
325 }
326 }
327
328 pub fn write_as<M: Memory, T: Sized>(
330 &mut self,
331 memory: &mut M,
332 write: WasmMemoryWriteAs<T>,
333 obj: T,
334 gas_counter: &mut u64,
335 ) -> Result<(), MemoryAccessError> {
336 self.pre_process_memory_accesses(gas_counter)?;
337 write_memory_as(memory, write.ptr, obj).map_err(Into::into)
338 }
339}
340
341fn write_memory_as<T: Sized>(
343 memory: &mut impl Memory,
344 ptr: u32,
345 obj: T,
346) -> Result<(), MemoryError> {
347 let size = mem::size_of::<T>();
348 if size > 0 {
349 let slice = unsafe { slice::from_raw_parts(&obj as *const T as *const u8, size) };
359
360 memory.write(ptr, slice)
361 } else {
362 Ok(())
363 }
364}
365
366fn read_memory_as<T: Sized>(memory: &impl Memory, ptr: u32) -> Result<T, MemoryError> {
368 let mut buf = MaybeUninit::<T>::uninit();
369
370 let size = mem::size_of::<T>();
371 if size > 0 {
372 let mut_slice = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, size) };
384
385 memory.read(ptr, mut_slice)?;
386 }
387
388 Ok(unsafe { buf.assume_init() })
395}
396
397pub struct WasmMemoryReadAs<T> {
399 pub(crate) ptr: u32,
400 pub(crate) _phantom: PhantomData<T>,
401}
402
403pub struct WasmMemoryReadDecoded<T: Decode + MaxEncodedLen> {
405 pub(crate) ptr: u32,
406 pub(crate) _phantom: PhantomData<T>,
407}
408
409pub struct WasmMemoryRead {
411 pub(crate) ptr: u32,
412 pub(crate) size: u32,
413}
414
415pub struct WasmMemoryWriteAs<T> {
417 pub(crate) ptr: u32,
418 pub(crate) _phantom: PhantomData<T>,
419}
420
421pub struct WasmMemoryWrite {
423 pub(crate) ptr: u32,
424 pub(crate) size: u32,
425}