diff --git a/programs/bpf_loader/src/syscalls/mem_ops.rs b/programs/bpf_loader/src/syscalls/mem_ops.rs index fa2ab3c3ccef08..37f158811105e2 100644 --- a/programs/bpf_loader/src/syscalls/mem_ops.rs +++ b/programs/bpf_loader/src/syscalls/mem_ops.rs @@ -530,7 +530,7 @@ impl<'a> Iterator for MemoryChunkIterator<'a> { account_index = account_index.saturating_add(1); self.account_index = Some(account_index); } else { - region_is_account = region.vm_addr == account_addr + region_is_account = (account.original_data_len != 0 && region.vm_addr == account_addr) // unaligned programs do not have a resize area || (self.resize_area && region.vm_addr == resize_addr); break; @@ -604,7 +604,7 @@ impl DoubleEndedIterator for MemoryChunkIterator<'_> { self.account_index = Some(account_index); } else { - region_is_account = region.vm_addr == account_addr + region_is_account = (account.original_data_len != 0 && region.vm_addr == account_addr) // unaligned programs do not have a resize area || (self.resize_area && region.vm_addr == resize_addr); break; diff --git a/programs/sbf/rust/account_mem/src/lib.rs b/programs/sbf/rust/account_mem/src/lib.rs index fe343b17dd9bef..989a4a7ee9635e 100644 --- a/programs/sbf/rust/account_mem/src/lib.rs +++ b/programs/sbf/rust/account_mem/src/lib.rs @@ -60,8 +60,15 @@ pub fn process_instruction( sol_memset(&mut data[data_len.saturating_sub(2)..], 0, 3); } 5 => { + // memcmp overlaps begining + #[allow(clippy::manual_memcpy)] + for i in 0..3 { + buf[i] = too_early(2)[i]; + } + // memset overlaps begin of account area sol_memset(too_early(2), 3, 3); + sol_memcpy(too_early(2), &buf, 3); } 6 => { // memcpy src overlaps end of account diff --git a/programs/sbf/rust/account_mem_deprecated/src/lib.rs b/programs/sbf/rust/account_mem_deprecated/src/lib.rs index 74643a9e6510b3..59ac880a4cb465 100644 --- a/programs/sbf/rust/account_mem_deprecated/src/lib.rs +++ b/programs/sbf/rust/account_mem_deprecated/src/lib.rs @@ -25,7 +25,7 @@ pub fn process_instruction( let mut too_early = |before: usize| -> &mut [u8] { let data = data.as_mut_ptr().wrapping_sub(before); - unsafe { std::slice::from_raw_parts_mut(data, data_len) } + unsafe { std::slice::from_raw_parts_mut(data, data_len.wrapping_add(100)) } }; match instruction_data[0] { @@ -40,11 +40,11 @@ pub fn process_instruction( 2 => { // memcmp overlaps begining #[allow(clippy::manual_memcpy)] - for i in 0..500 { + for i in 0..90 { buf[i] = too_early(8)[i]; } - sol_memcmp(too_early(8), &buf, 500); + sol_memcmp(too_early(8), &buf, 90); } 3 => { // memcmp overlaps begining diff --git a/programs/sbf/tests/programs.rs b/programs/sbf/tests/programs.rs index 51eef2f8aaf7d5..cfd1f28acad077 100644 --- a/programs/sbf/tests/programs.rs +++ b/programs/sbf/tests/programs.rs @@ -5194,6 +5194,29 @@ fn test_mem_syscalls_overlap_account_begin_or_end() { assert!(!logs.last().unwrap().ends_with(" failed: InvalidLength")); } } + + let account = AccountSharedData::new(42, 0, &program_id); + bank.store_account(&account_keypair.pubkey(), &account); + + for instr in 0..=15 { + println!("Testing deprecated:{deprecated} direct_mapping:{direct_mapping} instruction:{instr} zero-length account"); + let instruction = + Instruction::new_with_bytes(program_id, &[instr, 0], account_metas.clone()); + + let message = Message::new(&[instruction], Some(&mint_pubkey)); + let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash()); + let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx); + + if direct_mapping && !deprecated { + // we have a resize area + assert!( + logs.last().unwrap().ends_with(" failed: InvalidLength"), + "{logs:?}" + ); + } else { + assert!(result.is_ok(), "{logs:?}"); + } + } } } }