Feature - Check syscall outputs do not overlap (#28599)
* Extends is_nonoverlapping() to be able to deal with two different lengths. * Uses is_nonoverlapping() for syscall output parameters. * Feature gates the new throws of SyscallError::CopyOverlapping. * Adds tests which trigger SyscallError::CopyOverlapping.
This commit is contained in:
parent
7b70aef33c
commit
a43098a428
|
@ -26,7 +26,7 @@ declare_syscall!(
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&check_physical_overlapping::id());
|
.is_active(&check_physical_overlapping::id());
|
||||||
|
|
||||||
if !is_nonoverlapping(src_addr, dst_addr, n) {
|
if !is_nonoverlapping(src_addr, n, dst_addr, n) {
|
||||||
return Err(SyscallError::CopyOverlapping.into());
|
return Err(SyscallError::CopyOverlapping.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ declare_syscall!(
|
||||||
)?
|
)?
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
if do_check_physical_overlapping
|
if do_check_physical_overlapping
|
||||||
&& !is_nonoverlapping(src_ptr as usize, dst_ptr as usize, n as usize)
|
&& !is_nonoverlapping(src_ptr as usize, n as usize, dst_ptr as usize, n as usize)
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
std::ptr::copy(src_ptr, dst_ptr, n as usize);
|
std::ptr::copy(src_ptr, dst_ptr, n as usize);
|
||||||
|
|
|
@ -30,7 +30,8 @@ use {
|
||||||
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
||||||
feature_set::FeatureSet,
|
feature_set::FeatureSet,
|
||||||
feature_set::{
|
feature_set::{
|
||||||
self, blake3_syscall_enabled, check_physical_overlapping, curve25519_syscall_enabled,
|
self, blake3_syscall_enabled, check_physical_overlapping,
|
||||||
|
check_syscall_outputs_do_not_overlap, curve25519_syscall_enabled,
|
||||||
disable_cpi_setting_executable_and_rent_epoch, disable_fees_sysvar,
|
disable_cpi_setting_executable_and_rent_epoch, disable_fees_sysvar,
|
||||||
enable_early_verification_of_account_modifications, libsecp256k1_0_5_upgrade_enabled,
|
enable_early_verification_of_account_modifications, libsecp256k1_0_5_upgrade_enabled,
|
||||||
limit_secp256k1_recovery_id, stop_sibling_instruction_search_at_parent,
|
limit_secp256k1_recovery_id, stop_sibling_instruction_search_at_parent,
|
||||||
|
@ -649,10 +650,21 @@ declare_syscall!(
|
||||||
let address = translate_slice_mut::<u8>(
|
let address = translate_slice_mut::<u8>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
address_addr,
|
address_addr,
|
||||||
32,
|
std::mem::size_of::<Pubkey>() as u64,
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
|
if !is_nonoverlapping(
|
||||||
|
bump_seed_ref as *const _ as usize,
|
||||||
|
std::mem::size_of_val(bump_seed_ref),
|
||||||
|
address.as_ptr() as usize,
|
||||||
|
std::mem::size_of::<Pubkey>(),
|
||||||
|
) && invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&check_syscall_outputs_do_not_overlap::id())
|
||||||
|
{
|
||||||
|
return Err(SyscallError::CopyOverlapping.into());
|
||||||
|
}
|
||||||
*bump_seed_ref = bump_seed[0];
|
*bump_seed_ref = bump_seed[0];
|
||||||
address.copy_from_slice(new_address.as_ref());
|
address.copy_from_slice(new_address.as_ref());
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
|
@ -1432,6 +1444,18 @@ declare_syscall!(
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if !is_nonoverlapping(
|
||||||
|
to_slice.as_ptr() as usize,
|
||||||
|
length as usize,
|
||||||
|
program_id_result as *const _ as usize,
|
||||||
|
std::mem::size_of::<Pubkey>(),
|
||||||
|
) && invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&check_syscall_outputs_do_not_overlap::id())
|
||||||
|
{
|
||||||
|
return Err(SyscallError::CopyOverlapping.into());
|
||||||
|
}
|
||||||
|
|
||||||
*program_id_result = *program_id;
|
*program_id_result = *program_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1490,17 +1514,14 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(instruction_context) = found_instruction_context {
|
if let Some(instruction_context) = found_instruction_context {
|
||||||
let ProcessedSiblingInstruction {
|
let result_header = translate_type_mut::<ProcessedSiblingInstruction>(
|
||||||
data_len,
|
|
||||||
accounts_len,
|
|
||||||
} = translate_type_mut::<ProcessedSiblingInstruction>(
|
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
meta_addr,
|
meta_addr,
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if *data_len == (instruction_context.get_instruction_data().len() as u64)
|
if result_header.data_len == (instruction_context.get_instruction_data().len() as u64)
|
||||||
&& *accounts_len
|
&& result_header.accounts_len
|
||||||
== (instruction_context.get_number_of_instruction_accounts() as u64)
|
== (instruction_context.get_number_of_instruction_accounts() as u64)
|
||||||
{
|
{
|
||||||
let program_id = translate_type_mut::<Pubkey>(
|
let program_id = translate_type_mut::<Pubkey>(
|
||||||
|
@ -1511,18 +1532,58 @@ declare_syscall!(
|
||||||
let data = translate_slice_mut::<u8>(
|
let data = translate_slice_mut::<u8>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
data_addr,
|
data_addr,
|
||||||
*data_len as u64,
|
result_header.data_len as u64,
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
let accounts = translate_slice_mut::<AccountMeta>(
|
let accounts = translate_slice_mut::<AccountMeta>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
accounts_addr,
|
accounts_addr,
|
||||||
*accounts_len as u64,
|
result_header.accounts_len as u64,
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
invoke_context.get_check_size(),
|
invoke_context.get_check_size(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if (!is_nonoverlapping(
|
||||||
|
result_header as *const _ as usize,
|
||||||
|
std::mem::size_of::<ProcessedSiblingInstruction>(),
|
||||||
|
program_id as *const _ as usize,
|
||||||
|
std::mem::size_of::<Pubkey>(),
|
||||||
|
) || !is_nonoverlapping(
|
||||||
|
result_header as *const _ as usize,
|
||||||
|
std::mem::size_of::<ProcessedSiblingInstruction>(),
|
||||||
|
accounts.as_ptr() as usize,
|
||||||
|
std::mem::size_of::<AccountMeta>()
|
||||||
|
.saturating_mul(result_header.accounts_len as usize),
|
||||||
|
) || !is_nonoverlapping(
|
||||||
|
result_header as *const _ as usize,
|
||||||
|
std::mem::size_of::<ProcessedSiblingInstruction>(),
|
||||||
|
data.as_ptr() as usize,
|
||||||
|
result_header.data_len as usize,
|
||||||
|
) || !is_nonoverlapping(
|
||||||
|
program_id as *const _ as usize,
|
||||||
|
std::mem::size_of::<Pubkey>(),
|
||||||
|
data.as_ptr() as usize,
|
||||||
|
result_header.data_len as usize,
|
||||||
|
) || !is_nonoverlapping(
|
||||||
|
program_id as *const _ as usize,
|
||||||
|
std::mem::size_of::<Pubkey>(),
|
||||||
|
accounts.as_ptr() as usize,
|
||||||
|
std::mem::size_of::<AccountMeta>()
|
||||||
|
.saturating_mul(result_header.accounts_len as usize),
|
||||||
|
) || !is_nonoverlapping(
|
||||||
|
data.as_ptr() as usize,
|
||||||
|
result_header.data_len as usize,
|
||||||
|
accounts.as_ptr() as usize,
|
||||||
|
std::mem::size_of::<AccountMeta>()
|
||||||
|
.saturating_mul(result_header.accounts_len as usize),
|
||||||
|
)) && invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&check_syscall_outputs_do_not_overlap::id())
|
||||||
|
{
|
||||||
|
return Err(SyscallError::CopyOverlapping.into());
|
||||||
|
}
|
||||||
|
|
||||||
*program_id = *instruction_context
|
*program_id = *instruction_context
|
||||||
.get_last_program_key(invoke_context.transaction_context)
|
.get_last_program_key(invoke_context.transaction_context)
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
|
@ -1548,8 +1609,9 @@ declare_syscall!(
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
accounts.clone_from_slice(account_metas.as_slice());
|
accounts.clone_from_slice(account_metas.as_slice());
|
||||||
}
|
}
|
||||||
*data_len = instruction_context.get_instruction_data().len() as u64;
|
result_header.data_len = instruction_context.get_instruction_data().len() as u64;
|
||||||
*accounts_len = instruction_context.get_number_of_instruction_accounts() as u64;
|
result_header.accounts_len =
|
||||||
|
instruction_context.get_number_of_instruction_accounts() as u64;
|
||||||
return Ok(true as u64);
|
return Ok(true as u64);
|
||||||
}
|
}
|
||||||
Ok(false as u64)
|
Ok(false as u64)
|
||||||
|
@ -1603,7 +1665,7 @@ declare_syscall!(
|
||||||
let instruction_context = transaction_context
|
let instruction_context = transaction_context
|
||||||
.get_current_instruction_context()
|
.get_current_instruction_context()
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
let updates = translate_slice_mut::<AccountPropertyUpdate>(
|
let updates = translate_slice::<AccountPropertyUpdate>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
updates_addr,
|
updates_addr,
|
||||||
updates_count,
|
updates_count,
|
||||||
|
@ -1621,7 +1683,7 @@ declare_syscall!(
|
||||||
unsafe { std::mem::transmute::<_, TransactionContextAttribute>(update.attribute) };
|
unsafe { std::mem::transmute::<_, TransactionContextAttribute>(update.attribute) };
|
||||||
match attribute {
|
match attribute {
|
||||||
TransactionContextAttribute::TransactionAccountOwner => {
|
TransactionContextAttribute::TransactionAccountOwner => {
|
||||||
let owner_pubkey = translate_type_mut::<Pubkey>(
|
let owner_pubkey = translate_type::<Pubkey>(
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
update.value,
|
update.value,
|
||||||
invoke_context.get_check_aligned(),
|
invoke_context.get_check_aligned(),
|
||||||
|
@ -3620,6 +3682,7 @@ mod tests {
|
||||||
invoke_context: &'a mut InvokeContext<'b>,
|
invoke_context: &'a mut InvokeContext<'b>,
|
||||||
seeds: &[&[u8]],
|
seeds: &[&[u8]],
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
|
overlap_outputs: bool,
|
||||||
syscall: SyscallFunction<&'a mut InvokeContext<'b>>,
|
syscall: SyscallFunction<&'a mut InvokeContext<'b>>,
|
||||||
) -> Result<(Pubkey, u8), EbpfError> {
|
) -> Result<(Pubkey, u8), EbpfError> {
|
||||||
const SEEDS_VA: u64 = 0x100000000;
|
const SEEDS_VA: u64 = 0x100000000;
|
||||||
|
@ -3687,7 +3750,11 @@ mod tests {
|
||||||
seeds.len() as u64,
|
seeds.len() as u64,
|
||||||
PROGRAM_ID_VA,
|
PROGRAM_ID_VA,
|
||||||
ADDRESS_VA,
|
ADDRESS_VA,
|
||||||
BUMP_SEED_VA,
|
if overlap_outputs {
|
||||||
|
ADDRESS_VA
|
||||||
|
} else {
|
||||||
|
BUMP_SEED_VA
|
||||||
|
},
|
||||||
&mut memory_mapping,
|
&mut memory_mapping,
|
||||||
&mut result,
|
&mut result,
|
||||||
);
|
);
|
||||||
|
@ -3703,6 +3770,7 @@ mod tests {
|
||||||
invoke_context,
|
invoke_context,
|
||||||
seeds,
|
seeds,
|
||||||
address,
|
address,
|
||||||
|
false,
|
||||||
SyscallCreateProgramAddress::call,
|
SyscallCreateProgramAddress::call,
|
||||||
)?;
|
)?;
|
||||||
Ok(address)
|
Ok(address)
|
||||||
|
@ -3717,10 +3785,85 @@ mod tests {
|
||||||
invoke_context,
|
invoke_context,
|
||||||
seeds,
|
seeds,
|
||||||
address,
|
address,
|
||||||
|
false,
|
||||||
SyscallTryFindProgramAddress::call,
|
SyscallTryFindProgramAddress::call,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_and_get_return_data() {
|
||||||
|
const SRC_VA: u64 = 0x100000000;
|
||||||
|
const DST_VA: u64 = 0x200000000;
|
||||||
|
const PROGRAM_ID_VA: u64 = 0x300000000;
|
||||||
|
let data = vec![42; 24];
|
||||||
|
let mut data_buffer = vec![0; 16];
|
||||||
|
let mut id_buffer = vec![0; 32];
|
||||||
|
|
||||||
|
let config = Config::default();
|
||||||
|
let mut memory_mapping = MemoryMapping::new(
|
||||||
|
vec![
|
||||||
|
MemoryRegion::new_readonly(&data, SRC_VA),
|
||||||
|
MemoryRegion::new_writable(&mut data_buffer, DST_VA),
|
||||||
|
MemoryRegion::new_writable(&mut id_buffer, PROGRAM_ID_VA),
|
||||||
|
],
|
||||||
|
&config,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
prepare_mockup!(
|
||||||
|
invoke_context,
|
||||||
|
transaction_context,
|
||||||
|
program_id,
|
||||||
|
bpf_loader::id(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut result = ProgramResult::Ok(0);
|
||||||
|
SyscallSetReturnData::call(
|
||||||
|
&mut invoke_context,
|
||||||
|
SRC_VA,
|
||||||
|
data.len() as u64,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut memory_mapping,
|
||||||
|
&mut result,
|
||||||
|
);
|
||||||
|
assert_eq!(result.unwrap(), 0);
|
||||||
|
|
||||||
|
let mut result = ProgramResult::Ok(0);
|
||||||
|
SyscallGetReturnData::call(
|
||||||
|
&mut invoke_context,
|
||||||
|
DST_VA,
|
||||||
|
data_buffer.len() as u64,
|
||||||
|
PROGRAM_ID_VA,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut memory_mapping,
|
||||||
|
&mut result,
|
||||||
|
);
|
||||||
|
assert_eq!(result.unwrap() as usize, data.len());
|
||||||
|
assert_eq!(data.get(0..data_buffer.len()).unwrap(), data_buffer);
|
||||||
|
assert_eq!(id_buffer, program_id.to_bytes());
|
||||||
|
|
||||||
|
let mut result = ProgramResult::Ok(0);
|
||||||
|
SyscallGetReturnData::call(
|
||||||
|
&mut invoke_context,
|
||||||
|
PROGRAM_ID_VA,
|
||||||
|
data_buffer.len() as u64,
|
||||||
|
PROGRAM_ID_VA,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut memory_mapping,
|
||||||
|
&mut result,
|
||||||
|
);
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
||||||
|
SyscallError::CopyOverlapping
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_syscall_sol_get_processed_sibling_instruction() {
|
fn test_syscall_sol_get_processed_sibling_instruction() {
|
||||||
let transaction_accounts = (0..9)
|
let transaction_accounts = (0..9)
|
||||||
|
@ -3859,6 +4002,28 @@ mod tests {
|
||||||
&mut result,
|
&mut result,
|
||||||
);
|
);
|
||||||
assert_eq!(result.unwrap(), 0);
|
assert_eq!(result.unwrap(), 0);
|
||||||
|
|
||||||
|
invoke_context
|
||||||
|
.get_compute_meter()
|
||||||
|
.borrow_mut()
|
||||||
|
.mock_set_remaining(syscall_base_cost);
|
||||||
|
let mut result = ProgramResult::Ok(0);
|
||||||
|
SyscallGetProcessedSiblingInstruction::call(
|
||||||
|
&mut invoke_context,
|
||||||
|
0,
|
||||||
|
VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
|
||||||
|
VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
|
||||||
|
VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
|
||||||
|
VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64),
|
||||||
|
&mut memory_mapping,
|
||||||
|
&mut result,
|
||||||
|
);
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
ProgramResult::Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
||||||
|
SyscallError::CopyOverlapping
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4219,6 +4384,19 @@ mod tests {
|
||||||
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded)
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
call_program_address_common(
|
||||||
|
&mut invoke_context,
|
||||||
|
seeds,
|
||||||
|
&address,
|
||||||
|
true,
|
||||||
|
SyscallTryFindProgramAddress::call,
|
||||||
|
),
|
||||||
|
Err(EbpfError::UserError(error)) if error.downcast_ref::<BpfError>().unwrap() == &BpfError::SyscallError(
|
||||||
|
SyscallError::CopyOverlapping
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub trait SyscallStubs: Sync + Send {
|
||||||
unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
|
unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
|
||||||
// cannot be overlapping
|
// cannot be overlapping
|
||||||
assert!(
|
assert!(
|
||||||
is_nonoverlapping(src as usize, dst as usize, n),
|
is_nonoverlapping(src as usize, n, dst as usize, n),
|
||||||
"memcpy does not support overlapping regions"
|
"memcpy does not support overlapping regions"
|
||||||
);
|
);
|
||||||
std::ptr::copy_nonoverlapping(src, dst, n as usize);
|
std::ptr::copy_nonoverlapping(src, dst, n as usize);
|
||||||
|
@ -207,18 +207,20 @@ pub(crate) fn sol_set_account_properties(updates: &[AccountPropertyUpdate]) {
|
||||||
|
|
||||||
/// Check that two regions do not overlap.
|
/// Check that two regions do not overlap.
|
||||||
///
|
///
|
||||||
/// Adapted from libcore, hidden to share with bpf_loader without being part of
|
/// Hidden to share with bpf_loader without being part of the API surface.
|
||||||
/// the API surface.
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn is_nonoverlapping<N>(src: N, dst: N, count: N) -> bool
|
pub fn is_nonoverlapping<N>(src: N, src_len: N, dst: N, dst_len: N) -> bool
|
||||||
where
|
where
|
||||||
N: Ord + std::ops::Sub<Output = N>,
|
N: Ord + std::ops::Sub<Output = N>,
|
||||||
<N as std::ops::Sub>::Output: Ord,
|
<N as std::ops::Sub>::Output: Ord,
|
||||||
{
|
{
|
||||||
let diff = if src > dst { src - dst } else { dst - src };
|
// If the absolute distance between the ptrs is at least as big as the size of the other,
|
||||||
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
|
|
||||||
// they do not overlap.
|
// they do not overlap.
|
||||||
diff >= count
|
if src > dst {
|
||||||
|
src - dst >= dst_len
|
||||||
|
} else {
|
||||||
|
dst - src >= src_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -227,12 +229,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_nonoverlapping() {
|
fn test_is_nonoverlapping() {
|
||||||
assert!(is_nonoverlapping(10, 7, 3));
|
for dst in 0..8 {
|
||||||
assert!(!is_nonoverlapping(10, 8, 3));
|
assert!(is_nonoverlapping(10, 3, dst, 3));
|
||||||
assert!(!is_nonoverlapping(10, 9, 3));
|
}
|
||||||
assert!(!is_nonoverlapping(10, 10, 3));
|
for dst in 8..13 {
|
||||||
assert!(!is_nonoverlapping(10, 11, 3));
|
assert!(!is_nonoverlapping(10, 3, dst, 3));
|
||||||
assert!(!is_nonoverlapping(10, 12, 3));
|
}
|
||||||
assert!(is_nonoverlapping(10, 13, 3));
|
for dst in 13..20 {
|
||||||
|
assert!(is_nonoverlapping(10, 3, dst, 3));
|
||||||
|
}
|
||||||
|
assert!(is_nonoverlapping::<u8>(255, 3, 254, 1));
|
||||||
|
assert!(!is_nonoverlapping::<u8>(255, 2, 254, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,6 +530,10 @@ pub mod limit_max_instruction_trace_length {
|
||||||
solana_sdk::declare_id!("GQALDaC48fEhZGWRj9iL5Q889emJKcj3aCvHF7VCbbF4");
|
solana_sdk::declare_id!("GQALDaC48fEhZGWRj9iL5Q889emJKcj3aCvHF7VCbbF4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod check_syscall_outputs_do_not_overlap {
|
||||||
|
solana_sdk::declare_id!("3uRVPBpyEJRo1emLCrq38eLRFGcu6uKSpUXqGvU8T7SZ");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
|
@ -656,7 +660,8 @@ lazy_static! {
|
||||||
(epoch_accounts_hash::id(), "enable epoch accounts hash calculation #27539"),
|
(epoch_accounts_hash::id(), "enable epoch accounts hash calculation #27539"),
|
||||||
(remove_deprecated_request_unit_ix::id(), "remove support for RequestUnitsDeprecated instruction #27500"),
|
(remove_deprecated_request_unit_ix::id(), "remove support for RequestUnitsDeprecated instruction #27500"),
|
||||||
(increase_tx_account_lock_limit::id(), "increase tx account lock limit to 128 #27241"),
|
(increase_tx_account_lock_limit::id(), "increase tx account lock limit to 128 #27241"),
|
||||||
(limit_max_instruction_trace_length::id(), "limit max instruction trace length"),
|
(limit_max_instruction_trace_length::id(), "limit max instruction trace length #27939"),
|
||||||
|
(check_syscall_outputs_do_not_overlap::id(), "check syscall outputs do_not overlap #28600"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue