sc_executor_wasmtime/
util.rs1use crate::{runtime::StoreData, InstantiationStrategy};
20use sc_executor_common::{
21 error::{Error, Result},
22 util::checked_range,
23};
24use sp_wasm_interface::Pointer;
25use wasmtime::{AsContext, AsContextMut};
26
27pub(crate) fn read_memory_into(
31 ctx: impl AsContext<Data = StoreData>,
32 address: Pointer<u8>,
33 dest: &mut [u8],
34) -> Result<()> {
35 let memory = ctx.as_context().data().memory().data(&ctx);
36
37 let range = checked_range(address.into(), dest.len(), memory.len())
38 .ok_or_else(|| Error::Other("memory read is out of bounds".into()))?;
39 dest.copy_from_slice(&memory[range]);
40 Ok(())
41}
42
43pub(crate) fn write_memory_from(
47 mut ctx: impl AsContextMut<Data = StoreData>,
48 address: Pointer<u8>,
49 data: &[u8],
50) -> Result<()> {
51 let memory = ctx.as_context().data().memory();
52 let memory = memory.data_mut(&mut ctx);
53
54 let range = checked_range(address.into(), data.len(), memory.len())
55 .ok_or_else(|| Error::Other("memory write is out of bounds".into()))?;
56 memory[range].copy_from_slice(data);
57 Ok(())
58}
59
60#[cfg(target_os = "linux")]
65fn is_madvise_working() -> std::result::Result<bool, String> {
66 let page_size = rustix::param::page_size();
67
68 unsafe {
69 let pointer = rustix::mm::mmap_anonymous(
71 std::ptr::null_mut(),
72 2 * page_size,
73 rustix::mm::ProtFlags::READ | rustix::mm::ProtFlags::WRITE,
74 rustix::mm::MapFlags::PRIVATE,
75 )
76 .map_err(|error| format!("mmap failed: {}", error))?;
77
78 std::ptr::write_volatile(pointer.cast::<u8>(), b'A');
80 std::ptr::write_volatile(pointer.cast::<u8>().add(page_size), b'B');
81
82 let result_madvise =
84 rustix::mm::madvise(pointer, page_size, rustix::mm::Advice::LinuxDontNeed)
85 .map_err(|error| format!("madvise failed: {}", error));
86
87 let value_1 = std::ptr::read_volatile(pointer.cast::<u8>());
89 let value_2 = std::ptr::read_volatile(pointer.cast::<u8>().add(page_size));
90
91 let result_munmap = rustix::mm::munmap(pointer, 2 * page_size)
92 .map_err(|error| format!("munmap failed: {}", error));
93
94 result_madvise?;
95 result_munmap?;
96
97 Ok(value_1 == 0 && value_2 == b'B')
99 }
100}
101
102#[cfg(test)]
103#[cfg(target_os = "linux")]
104#[test]
105fn test_is_madvise_working_check_does_not_fail() {
106 assert!(is_madvise_working().is_ok());
107}
108
109#[cfg(target_os = "linux")]
112pub(crate) fn replace_strategy_if_broken(strategy: &mut InstantiationStrategy) {
113 let replacement_strategy = match *strategy {
114 InstantiationStrategy::Pooling | InstantiationStrategy::RecreateInstance => return,
116
117 InstantiationStrategy::PoolingCopyOnWrite => InstantiationStrategy::Pooling,
119 InstantiationStrategy::RecreateInstanceCopyOnWrite =>
120 InstantiationStrategy::RecreateInstance,
121 };
122
123 use std::sync::OnceLock;
124 static IS_OK: OnceLock<bool> = OnceLock::new();
125
126 let is_ok = IS_OK.get_or_init(|| {
127 let is_ok = match is_madvise_working() {
128 Ok(is_ok) => is_ok,
129 Err(error) => {
130 log::warn!("Failed to check whether `madvise(MADV_DONTNEED)` works: {}", error);
132 false
133 }
134 };
135
136 if !is_ok {
137 log::warn!("You're running on a system with a broken `madvise(MADV_DONTNEED)` implementation. This will result in lower performance.");
138 }
139
140 is_ok
141 });
142
143 if !is_ok {
144 *strategy = replacement_strategy;
145 }
146}
147
148#[cfg(not(target_os = "linux"))]
149pub(crate) fn replace_strategy_if_broken(_: &mut InstantiationStrategy) {}