Skip to content

Commit 243238a

Browse files
stegaBOBfebo
andauthored
Feat: make AccountInfo::data_ptr public (#232)
* make data_ptr public * Update sdk/pinocchio/src/account_info.rs Co-authored-by: Fernando Otero <[email protected]> * add some tests for data ptr * Fix spelling --------- Co-authored-by: Fernando Otero <[email protected]>
1 parent 8935d5d commit 243238a

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

sdk/pinocchio/src/account_info.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,13 @@ impl AccountInfo {
625625
}
626626

627627
/// Returns the memory address of the account data.
628-
fn data_ptr(&self) -> *mut u8 {
628+
/// # Important
629+
///
630+
/// Obtaining the raw pointer itself is safe, but de-referencing it requires
631+
/// the caller to uphold Rust's aliasing rules. It is undefined behavior to de-reference
632+
/// the pointer or write through it while any safe reference (e.g., from any of `borrow_data`
633+
/// or `borrow_mut_data` methods) to the same data is still alive.
634+
pub fn data_ptr(&self) -> *mut u8 {
629635
unsafe { (self.raw as *mut u8).add(core::mem::size_of::<Account>()) }
630636
}
631637
}
@@ -924,8 +930,8 @@ mod tests {
924930
#[test]
925931
fn test_borrow_data() {
926932
// 8-bytes aligned account data.
927-
let mut data = [0u64; size_of::<Account>() / size_of::<u64>()];
928-
// Set the borrow state.
933+
let mut data = [0u64; size_of::<Account>() / size_of::<u64>() + 1]; // extra byte at end for account data
934+
// Set the borrow state.
929935
data[0] = NOT_BORROWED as u64;
930936
let account_info = AccountInfo {
931937
raw: data.as_mut_ptr() as *mut Account,
@@ -937,6 +943,13 @@ mod tests {
937943
assert!(account_info.can_borrow_lamports().is_ok());
938944
assert!(account_info.can_borrow_mut_lamports().is_ok());
939945

946+
// It should be sound to mutate the data through the data pointer while no other borrows exist
947+
let data_ptr = account_info.data_ptr();
948+
unsafe {
949+
let data = core::slice::from_raw_parts_mut(data_ptr, 1); // Data is 1 byte long!
950+
data[0] = 1;
951+
}
952+
940953
// Borrow immutable data (7 immutable borrows available).
941954
const ACCOUNT_REF: MaybeUninit<Ref<[u8]>> = MaybeUninit::<Ref<[u8]>>::uninit();
942955
let mut refs = [ACCOUNT_REF; 7];
@@ -969,6 +982,8 @@ mod tests {
969982

970983
// Borrow mutable data.
971984
let ref_mut = account_info.try_borrow_mut_data().unwrap();
985+
// It should be sound to get the data pointer while the data is borrowed as long as we don't use it
986+
let _data_ptr = account_info.data_ptr();
972987

973988
// Check that we cannot borrow the data anymore.
974989
assert!(account_info.can_borrow_data().is_err());
@@ -1070,10 +1085,17 @@ mod tests {
10701085
assert_eq!(account.data_len(), 100);
10711086
assert_eq!(account.resize_delta(), 0);
10721087

1088+
// We should be able to get the data pointer whenever as long as we don't use it while the data is borrowed
1089+
let data_ptr_before = account.data_ptr();
1090+
10731091
// increase the size.
10741092

10751093
account.realloc(200, false).unwrap();
10761094

1095+
let data_ptr_after = account.data_ptr();
1096+
// The data pointer should point to the same address regardless of the reallocation
1097+
assert_eq!(data_ptr_before, data_ptr_after);
1098+
10771099
assert_eq!(account.data_len(), 200);
10781100
assert_eq!(account.resize_delta(), 100);
10791101

0 commit comments

Comments
 (0)