cpi: fix capacity check in update_caller_account (#34064)

reserve(additional) reserves additional bytes on top of the current _length_
not capacity. Before this fix we could potentially reserve less capacity than
required.
This commit is contained in:
Alessandro Decina 2023-11-15 22:42:12 +11:00 committed by GitHub
parent 7fd13c0cd2
commit d009d7304a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 6 deletions

View File

@ -1461,7 +1461,8 @@ fn update_caller_account(
// invalid address. // invalid address.
let min_capacity = caller_account.original_data_len; let min_capacity = caller_account.original_data_len;
if callee_account.capacity() < min_capacity { if callee_account.capacity() < min_capacity {
callee_account.reserve(min_capacity.saturating_sub(callee_account.capacity()))?; callee_account
.reserve(min_capacity.saturating_sub(callee_account.get_data().len()))?;
zero_all_mapped_spare_capacity = true; zero_all_mapped_spare_capacity = true;
} }

View File

@ -1288,6 +1288,33 @@ fn process_instruction(
}, },
&vec![0; original_data_len - new_len] &vec![0; original_data_len - new_len]
); );
// Realloc to [0xFC; 2]
invoke(
&create_instruction(
*callee_program_id,
&[
(accounts[ARGUMENT_INDEX].key, true, false),
(callee_program_id, false, false),
],
vec![0xFC; 2],
),
accounts,
)
.unwrap();
// Check that [2..20] is zeroed
let new_len = account.data_len();
assert_eq!(&*account.data.borrow(), &[0xFC; 2]);
assert_eq!(
unsafe {
slice::from_raw_parts(
account.data.borrow().as_ptr().add(new_len),
original_data_len - new_len,
)
},
&vec![0; original_data_len - new_len]
);
} }
TEST_WRITE_ACCOUNT => { TEST_WRITE_ACCOUNT => {
msg!("TEST_WRITE_ACCOUNT"); msg!("TEST_WRITE_ACCOUNT");

View File

@ -4420,12 +4420,18 @@ fn test_cpi_change_account_data_memory_allocation() {
// Test changing the account data both in place and by changing the // Test changing the account data both in place and by changing the
// underlying vector. CPI will have to detect the vector change and // underlying vector. CPI will have to detect the vector change and
// update the corresponding memory region. In both cases CPI will have // update the corresponding memory region. In all cases CPI will have
// to zero the spare bytes correctly. // to zero the spare bytes correctly.
if instruction_data[0] == 0xFE { match instruction_data[0] {
account.set_data(instruction_data.to_vec()); 0xFE => account.set_data(instruction_data.to_vec()),
} else { 0xFD => account.set_data_from_slice(instruction_data),
account.set_data_from_slice(instruction_data); 0xFC => {
// Exercise the update_caller_account capacity check where account len != capacity.
let mut data = instruction_data.to_vec();
data.reserve_exact(1);
account.set_data(data)
}
_ => panic!(),
} }
Ok(()) Ok(())