1#![cfg(not(target_os = "solana"))]
4
5use {
6 crate::{
7 account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
8 program_error::UNSUPPORTED_SYSVAR, pubkey::Pubkey,
9 },
10 itertools::Itertools,
11 std::sync::{Arc, RwLock},
12};
13
14lazy_static::lazy_static! {
15 static ref SYSCALL_STUBS: Arc<RwLock<Box<dyn SyscallStubs>>> = Arc::new(RwLock::new(Box::new(DefaultSyscallStubs {})));
16}
17
18pub fn set_syscall_stubs(syscall_stubs: Box<dyn SyscallStubs>) -> Box<dyn SyscallStubs> {
21 std::mem::replace(&mut SYSCALL_STUBS.write().unwrap(), syscall_stubs)
22}
23
24#[allow(clippy::integer_arithmetic)]
25pub trait SyscallStubs: Sync + Send {
26 fn sol_log(&self, message: &str) {
27 println!("{message}");
28 }
29 fn sol_log_compute_units(&self) {
30 sol_log("SyscallStubs: sol_log_compute_units() not available");
31 }
32 fn sol_invoke_signed(
33 &self,
34 _instruction: &Instruction,
35 _account_infos: &[AccountInfo],
36 _signers_seeds: &[&[&[u8]]],
37 ) -> ProgramResult {
38 sol_log("SyscallStubs: sol_invoke_signed() not available");
39 Ok(())
40 }
41 fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
42 UNSUPPORTED_SYSVAR
43 }
44 fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
45 UNSUPPORTED_SYSVAR
46 }
47 fn sol_get_fees_sysvar(&self, _var_addr: *mut u8) -> u64 {
48 UNSUPPORTED_SYSVAR
49 }
50 fn sol_get_rent_sysvar(&self, _var_addr: *mut u8) -> u64 {
51 UNSUPPORTED_SYSVAR
52 }
53 unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
55 assert!(
57 is_nonoverlapping(src as usize, n, dst as usize, n),
58 "memcpy does not support overlapping regions"
59 );
60 std::ptr::copy_nonoverlapping(src, dst, n);
61 }
62 unsafe fn sol_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
64 std::ptr::copy(src, dst, n);
65 }
66 unsafe fn sol_memcmp(&self, s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
68 let mut i = 0;
69 while i < n {
70 let a = *s1.add(i);
71 let b = *s2.add(i);
72 if a != b {
73 *result = a as i32 - b as i32;
74 return;
75 }
76 i += 1;
77 }
78 *result = 0
79 }
80 unsafe fn sol_memset(&self, s: *mut u8, c: u8, n: usize) {
82 let s = std::slice::from_raw_parts_mut(s, n);
83 for val in s.iter_mut().take(n) {
84 *val = c;
85 }
86 }
87 fn sol_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
88 None
89 }
90 fn sol_set_return_data(&self, _data: &[u8]) {}
91 fn sol_log_data(&self, fields: &[&[u8]]) {
92 println!("data: {}", fields.iter().map(base64::encode).join(" "));
93 }
94 fn sol_get_processed_sibling_instruction(&self, _index: usize) -> Option<Instruction> {
95 None
96 }
97 fn sol_get_stack_height(&self) -> u64 {
98 0
99 }
100}
101
102struct DefaultSyscallStubs {}
103impl SyscallStubs for DefaultSyscallStubs {}
104
105pub(crate) fn sol_log(message: &str) {
106 SYSCALL_STUBS.read().unwrap().sol_log(message);
107}
108
109pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
110 sol_log(&format!(
111 "{arg1:#x}, {arg2:#x}, {arg3:#x}, {arg4:#x}, {arg5:#x}"
112 ));
113}
114
115pub(crate) fn sol_log_compute_units() {
116 SYSCALL_STUBS.read().unwrap().sol_log_compute_units();
117}
118
119pub(crate) fn sol_invoke_signed(
120 instruction: &Instruction,
121 account_infos: &[AccountInfo],
122 signers_seeds: &[&[&[u8]]],
123) -> ProgramResult {
124 SYSCALL_STUBS
125 .read()
126 .unwrap()
127 .sol_invoke_signed(instruction, account_infos, signers_seeds)
128}
129
130pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 {
131 SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr)
132}
133
134pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
135 SYSCALL_STUBS
136 .read()
137 .unwrap()
138 .sol_get_epoch_schedule_sysvar(var_addr)
139}
140
141pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 {
142 SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr)
143}
144
145pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
146 SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
147}
148
149pub(crate) fn sol_memcpy(dst: *mut u8, src: *const u8, n: usize) {
150 unsafe {
151 SYSCALL_STUBS.read().unwrap().sol_memcpy(dst, src, n);
152 }
153}
154
155pub(crate) fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) {
156 unsafe {
157 SYSCALL_STUBS.read().unwrap().sol_memmove(dst, src, n);
158 }
159}
160
161pub(crate) fn sol_memcmp(s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
162 unsafe {
163 SYSCALL_STUBS.read().unwrap().sol_memcmp(s1, s2, n, result);
164 }
165}
166
167pub(crate) fn sol_memset(s: *mut u8, c: u8, n: usize) {
168 unsafe {
169 SYSCALL_STUBS.read().unwrap().sol_memset(s, c, n);
170 }
171}
172
173pub(crate) fn sol_get_return_data() -> Option<(Pubkey, Vec<u8>)> {
174 SYSCALL_STUBS.read().unwrap().sol_get_return_data()
175}
176
177pub(crate) fn sol_set_return_data(data: &[u8]) {
178 SYSCALL_STUBS.read().unwrap().sol_set_return_data(data)
179}
180
181pub(crate) fn sol_log_data(data: &[&[u8]]) {
182 SYSCALL_STUBS.read().unwrap().sol_log_data(data)
183}
184
185pub(crate) fn sol_get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
186 SYSCALL_STUBS
187 .read()
188 .unwrap()
189 .sol_get_processed_sibling_instruction(index)
190}
191
192pub(crate) fn sol_get_stack_height() -> u64 {
193 SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
194}
195
196#[doc(hidden)]
200pub fn is_nonoverlapping<N>(src: N, src_len: N, dst: N, dst_len: N) -> bool
201where
202 N: Ord + std::ops::Sub<Output = N>,
203 <N as std::ops::Sub>::Output: Ord,
204{
205 if src > dst {
208 src - dst >= dst_len
209 } else {
210 dst - src >= src_len
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_is_nonoverlapping() {
220 for dst in 0..8 {
221 assert!(is_nonoverlapping(10, 3, dst, 3));
222 }
223 for dst in 8..13 {
224 assert!(!is_nonoverlapping(10, 3, dst, 3));
225 }
226 for dst in 13..20 {
227 assert!(is_nonoverlapping(10, 3, dst, 3));
228 }
229 assert!(is_nonoverlapping::<u8>(255, 3, 254, 1));
230 assert!(!is_nonoverlapping::<u8>(255, 2, 254, 3));
231 }
232}