diff --git a/programs/bpf/c/src/invoke/invoke.c b/programs/bpf/c/src/invoke/invoke.c index 0c8927b0b4..2318b962e2 100644 --- a/programs/bpf/c/src/invoke/invoke.c +++ b/programs/bpf/c/src/invoke/invoke.c @@ -115,6 +115,18 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); } + sol_log("Test no instruction data"); + { + SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}}; + uint8_t data[] = {}; + const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, + arguments, SOL_ARRAY_SIZE(arguments), + data, SOL_ARRAY_SIZE(data)}; + + sol_assert(SUCCESS == + sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); + } + sol_log("Test return error"); { SolAccountMeta arguments[] = {{accounts[ARGUMENT_INDEX].key, true, true}}; diff --git a/programs/bpf/c/src/invoked/invoked.c b/programs/bpf/c/src/invoked/invoked.c index 2da8f8c5e7..b70b71f6de 100644 --- a/programs/bpf/c/src/invoked/invoked.c +++ b/programs/bpf/c/src/invoked/invoked.c @@ -12,6 +12,10 @@ extern uint64_t entrypoint(const uint8_t *input) { return ERROR_INVALID_ARGUMENT; } + if (params.data_len == 0) { + return SUCCESS; + } + switch (params.data[0]) { case TEST_VERIFY_TRANSLATIONS: { sol_log("verify data translations"); diff --git a/programs/bpf/rust/invoke/src/lib.rs b/programs/bpf/rust/invoke/src/lib.rs index 4fd842cc1c..eac71a6d09 100644 --- a/programs/bpf/rust/invoke/src/lib.rs +++ b/programs/bpf/rust/invoke/src/lib.rs @@ -117,6 +117,16 @@ fn process_instruction( invoke(&instruction, accounts)?; } + info!("Test no instruction data"); + { + let instruction = create_instruction( + *accounts[INVOKED_PROGRAM_INDEX].key, + &[(accounts[ARGUMENT_INDEX].key, true, true)], + vec![], + ); + invoke(&instruction, accounts)?; + } + info!("Test return error"); { let instruction = create_instruction( diff --git a/programs/bpf/rust/invoked/src/lib.rs b/programs/bpf/rust/invoked/src/lib.rs index ca88c135ba..d3495ec0f9 100644 --- a/programs/bpf/rust/invoked/src/lib.rs +++ b/programs/bpf/rust/invoked/src/lib.rs @@ -21,6 +21,10 @@ fn process_instruction( ) -> ProgramResult { info!("Invoked program"); + if instruction_data.is_empty() { + return Ok(()); + } + match instruction_data[0] { TEST_VERIFY_TRANSLATIONS => { info!("verify data translations"); diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index b212364822..ef2f745737 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -536,6 +536,7 @@ fn test_program_bpf_invoke() { invoked_program_id.clone(), invoked_program_id.clone(), invoked_program_id.clone(), + invoked_program_id.clone(), ] ); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 6f5aef9ade..8349ae8cd2 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -227,6 +227,8 @@ macro_rules! translate_slice_mut { && ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 { Err(SyscallError::UnalignedPointer.into()) + } else if $len == 0 { + Ok(unsafe { from_raw_parts_mut(0x1 as *mut $t, $len as usize) }) } else { match translate_addr::( $vm_addr as u64, @@ -1230,6 +1232,21 @@ mod tests { #[test] fn test_translate_slice() { + // zero len + let good_data = vec![1u8, 2, 3, 4, 5]; + let data: Vec = vec![]; + assert_eq!(0x1 as *const u8, data.as_ptr()); + let addr = good_data.as_ptr() as *const _ as u64; + let regions = vec![MemoryRegion { + addr_host: addr, + addr_vm: 100, + len: good_data.len() as u64, + }]; + let translated_data = + translate_slice!(u8, data.as_ptr(), data.len(), ®ions, &bpf_loader::id()).unwrap(); + assert_eq!(data, translated_data); + assert_eq!(0, translated_data.len()); + // u8 let mut data = vec![1u8, 2, 3, 4, 5]; let addr = data.as_ptr() as *const _ as u64;