@@ -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