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 as usize);
61 }
62 unsafe fn sol_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
64 std::ptr::copy(src, dst, n as usize);
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 "{:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
112 arg1, arg2, arg3, arg4, arg5
113 ));
114}
115
116pub(crate) fn sol_log_compute_units() {
117 SYSCALL_STUBS.read().unwrap().sol_log_compute_units();
118}
119
120pub(crate) fn sol_invoke_signed(
121 instruction: &Instruction,
122 account_infos: &[AccountInfo],
123 signers_seeds: &[&[&[u8]]],
124) -> ProgramResult {
125 SYSCALL_STUBS
126 .read()
127 .unwrap()
128 .sol_invoke_signed(instruction, account_infos, signers_seeds)
129}
130
131pub(crate) fn sol_get_clock_sysvar(var_addr: *mut u8) -> u64 {
132 SYSCALL_STUBS.read().unwrap().sol_get_clock_sysvar(var_addr)
133}
134
135pub(crate) fn sol_get_epoch_schedule_sysvar(var_addr: *mut u8) -> u64 {
136 SYSCALL_STUBS
137 .read()
138 .unwrap()
139 .sol_get_epoch_schedule_sysvar(var_addr)
140}
141
142pub(crate) fn sol_get_fees_sysvar(var_addr: *mut u8) -> u64 {
143 SYSCALL_STUBS.read().unwrap().sol_get_fees_sysvar(var_addr)
144}
145
146pub(crate) fn sol_get_rent_sysvar(var_addr: *mut u8) -> u64 {
147 SYSCALL_STUBS.read().unwrap().sol_get_rent_sysvar(var_addr)
148}
149
150pub(crate) fn sol_memcpy(dst: *mut u8, src: *const u8, n: usize) {
151 unsafe {
152 SYSCALL_STUBS.read().unwrap().sol_memcpy(dst, src, n);
153 }
154}
155
156pub(crate) fn sol_memmove(dst: *mut u8, src: *const u8, n: usize) {
157 unsafe {
158 SYSCALL_STUBS.read().unwrap().sol_memmove(dst, src, n);
159 }
160}
161
162pub(crate) fn sol_memcmp(s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
163 unsafe {
164 SYSCALL_STUBS.read().unwrap().sol_memcmp(s1, s2, n, result);
165 }
166}
167
168pub(crate) fn sol_memset(s: *mut u8, c: u8, n: usize) {
169 unsafe {
170 SYSCALL_STUBS.read().unwrap().sol_memset(s, c, n);
171 }
172}
173
174pub(crate) fn sol_get_return_data() -> Option<(Pubkey, Vec<u8>)> {
175 SYSCALL_STUBS.read().unwrap().sol_get_return_data()
176}
177
178pub(crate) fn sol_set_return_data(data: &[u8]) {
179 SYSCALL_STUBS.read().unwrap().sol_set_return_data(data)
180}
181
182pub(crate) fn sol_log_data(data: &[&[u8]]) {
183 SYSCALL_STUBS.read().unwrap().sol_log_data(data)
184}
185
186pub(crate) fn sol_get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
187 SYSCALL_STUBS
188 .read()
189 .unwrap()
190 .sol_get_processed_sibling_instruction(index)
191}
192
193pub(crate) fn sol_get_stack_height() -> u64 {
194 SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
195}
196
197#[doc(hidden)]
201pub fn is_nonoverlapping<N>(src: N, src_len: N, dst: N, dst_len: N) -> bool
202where
203 N: Ord + std::ops::Sub<Output = N>,
204 <N as std::ops::Sub>::Output: Ord,
205{
206 if src > dst {
209 src - dst >= dst_len
210 } else {
211 dst - src >= src_len
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn test_is_nonoverlapping() {
221 for dst in 0..8 {
222 assert!(is_nonoverlapping(10, 3, dst, 3));
223 }
224 for dst in 8..13 {
225 assert!(!is_nonoverlapping(10, 3, dst, 3));
226 }
227 for dst in 13..20 {
228 assert!(is_nonoverlapping(10, 3, dst, 3));
229 }
230 assert!(is_nonoverlapping::<u8>(255, 3, 254, 1));
231 assert!(!is_nonoverlapping::<u8>(255, 2, 254, 3));
232 }
233}