Skip to content

Commit ca3a98b

Browse files
authored
Clarify the use of constant values (#200)
* Add comments on constants * Improve offset comments * Add bitmask to dictionary * Renamed to field_at_offset
1 parent 5af8a54 commit ca3a98b

File tree

3 files changed

+92
-58
lines changed

3 files changed

+92
-58
lines changed

scripts/setup/solana.dic

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ callee
6363
RPC
6464
ed25519
6565
performant
66-
syscall/S
66+
syscall/S
67+
bitmask

sdk/pinocchio/src/account_info.rs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ pub const MAX_PERMITTED_DATA_INCREASE: usize = 1_024 * 10;
2222
pub enum BorrowState {
2323
/// Mask to check whether an account is already borrowed.
2424
///
25-
/// This will test both data and lamports borrow state.
25+
/// This will test both data and lamports borrow state. Any position
26+
/// in the borrow byte that is not set means that the account
27+
/// is borrowed in that state.
2628
Borrowed = 0b_1111_1111,
2729

2830
/// Mask to check whether an account is already mutably borrowed.
2931
///
30-
/// This will test both data and lamports mutable borrow state.
32+
/// This will test both data and lamports mutable borrow state. If
33+
/// one of the mutably borrowed bits is not set, then the account
34+
/// is mutably borrowed in that state.
3135
MutablyBorrowed = 0b_1000_1000,
3236
}
3337

@@ -261,18 +265,19 @@ impl AccountInfo {
261265
self.can_borrow_lamports()?;
262266

263267
let borrow_state = self.raw as *mut u8;
268+
// Use one immutable borrow for lamports by subtracting `1` from the
269+
// lamports borrow counter bits; we are guaranteed that there is at
270+
// least one immutable borrow available.
271+
//
264272
// SAFETY: The `borrow_state` is a mutable pointer to the borrow state
265273
// of the account, which is guaranteed to be valid.
266-
//
267-
// "consumes" one immutable borrow for lamports; we are guaranteed
268-
// that there is at least one immutable borrow available.
269-
unsafe { *borrow_state -= 1 << LAMPORTS_SHIFT };
274+
unsafe { *borrow_state -= 1 << LAMPORTS_BORROW_SHIFT };
270275

271276
// return the reference to lamports
272277
Ok(Ref {
273278
value: unsafe { NonNull::from(&(*self.raw).lamports) },
274279
state: unsafe { NonNull::new_unchecked(borrow_state) },
275-
borrow_shift: LAMPORTS_SHIFT,
280+
borrow_shift: LAMPORTS_BORROW_SHIFT,
276281
marker: PhantomData,
277282
})
278283
}
@@ -284,18 +289,18 @@ impl AccountInfo {
284289
self.can_borrow_mut_lamports()?;
285290

286291
let borrow_state = self.raw as *mut u8;
292+
// Set the mutable lamports borrow bit to `0`; we are guaranteed
293+
// that lamports are not already borrowed in any form.
294+
//
287295
// SAFETY: The `borrow_state` is a mutable pointer to the borrow state
288296
// of the account, which is guaranteed to be valid.
289-
//
290-
// "consumes" the mutable borrow for lamports; we are guaranteed
291-
// that lamports are not already borrowed in any form
292297
unsafe { *borrow_state &= 0b_0111_1111 };
293298

294299
// return the mutable reference to lamports
295300
Ok(RefMut {
296301
value: unsafe { NonNull::from(&mut (*self.raw).lamports) },
297302
state: unsafe { NonNull::new_unchecked(borrow_state) },
298-
borrow_mask: LAMPORTS_MASK,
303+
borrow_bitmask: LAMPORTS_MUTABLE_BORROW_BITMASK,
299304
marker: PhantomData,
300305
})
301306
}
@@ -314,12 +319,14 @@ impl AccountInfo {
314319
pub fn can_borrow_lamports(&self) -> Result<(), ProgramError> {
315320
let borrow_state = unsafe { (*self.raw).borrow_state };
316321

317-
// check if mutable borrow is already taken
318-
if borrow_state & 0b_1000_0000 != 0b_1000_0000 {
322+
// Check whether the mutable lamports borrow bit is already in
323+
// use (value `0`) or not. If it is `0`, then the borrow will fail.
324+
if borrow_state & LAMPORTS_MUTABLE_BORROW_BITMASK == 0 {
319325
return Err(ProgramError::AccountBorrowFailed);
320326
}
321327

322-
// check if we have reached the max immutable borrow count
328+
// Check whether we have reached the maximum immutable lamports borrow count
329+
// or not, i.e., it fails when all immutable lamports borrow bits are `0`.
323330
if borrow_state & 0b_0111_0000 == 0 {
324331
return Err(ProgramError::AccountBorrowFailed);
325332
}
@@ -341,7 +348,8 @@ impl AccountInfo {
341348
pub fn can_borrow_mut_lamports(&self) -> Result<(), ProgramError> {
342349
let borrow_state = unsafe { (*self.raw).borrow_state };
343350

344-
// check if any borrow (mutable or immutable) is already taken for lamports
351+
// Check whether any (mutable or immutable) lamports borrow bits are
352+
// in use (value `0`) or not.
345353
if borrow_state & 0b_1111_0000 != 0b_1111_0000 {
346354
return Err(ProgramError::AccountBorrowFailed);
347355
}
@@ -356,18 +364,19 @@ impl AccountInfo {
356364
self.can_borrow_data()?;
357365

358366
let borrow_state = self.raw as *mut u8;
367+
// Use one immutable borrow for data by subtracting `1` from the data
368+
// borrow counter bits; we are guaranteed that there is at least one
369+
// immutable borrow available.
370+
//
359371
// SAFETY: The `borrow_state` is a mutable pointer to the borrow state
360372
// of the account, which is guaranteed to be valid.
361-
//
362-
// "consumes" one immutable borrow for data; we are guaranteed
363-
// that there is at least one immutable borrow available
364373
unsafe { *borrow_state -= 1 };
365374

366375
// return the reference to data
367376
Ok(Ref {
368377
value: unsafe { NonNull::from(from_raw_parts(self.data_ptr(), self.data_len())) },
369378
state: unsafe { NonNull::new_unchecked(borrow_state) },
370-
borrow_shift: DATA_SHIFT,
379+
borrow_shift: DATA_BORROW_SHIFT,
371380
marker: PhantomData,
372381
})
373382
}
@@ -379,18 +388,18 @@ impl AccountInfo {
379388
self.can_borrow_mut_data()?;
380389

381390
let borrow_state = self.raw as *mut u8;
391+
// Set the mutable data borrow bit to `0`; we are guaranteed that account
392+
// data is not already borrowed in any form.
393+
//
382394
// SAFETY: The `borrow_state` is a mutable pointer to the borrow state
383395
// of the account, which is guaranteed to be valid.
384-
//
385-
// "consumes" the mutable borrow for account data; we are guaranteed
386-
// that account data are not already borrowed in any form
387396
unsafe { *borrow_state &= 0b_1111_0111 };
388397

389398
// return the mutable reference to data
390399
Ok(RefMut {
391400
value: unsafe { NonNull::from(from_raw_parts_mut(self.data_ptr(), self.data_len())) },
392401
state: unsafe { NonNull::new_unchecked(borrow_state) },
393-
borrow_mask: DATA_MASK,
402+
borrow_bitmask: DATA_MUTABLE_BORROW_BITMASK,
394403
marker: PhantomData,
395404
})
396405
}
@@ -409,13 +418,14 @@ impl AccountInfo {
409418
pub fn can_borrow_data(&self) -> Result<(), ProgramError> {
410419
let borrow_state = unsafe { (*self.raw).borrow_state };
411420

412-
// check if mutable data borrow is already taken (most significant bit
413-
// of the data borrow state)
414-
if borrow_state & 0b_0000_1000 == 0 {
421+
// Check whether the mutable data borrow bit is already in
422+
// use (value `0`) or not. If it is `0`, then the borrow will fail.
423+
if borrow_state & DATA_MUTABLE_BORROW_BITMASK == 0 {
415424
return Err(ProgramError::AccountBorrowFailed);
416425
}
417426

418-
// check if we have reached the max immutable data borrow count (7)
427+
// Check whether we have reached the maximum immutable data borrow count
428+
// or not, i.e., it fails when all immutable data borrow bits are `0`.
419429
if borrow_state & 0b_0000_0111 == 0 {
420430
return Err(ProgramError::AccountBorrowFailed);
421431
}
@@ -437,7 +447,8 @@ impl AccountInfo {
437447
pub fn can_borrow_mut_data(&self) -> Result<(), ProgramError> {
438448
let borrow_state = unsafe { (*self.raw).borrow_state };
439449

440-
// check if any borrow (mutable or immutable) is already taken for data
450+
// Check whether any (mutable or immutable) data borrow bits are
451+
// in use (value `0`) or not.
441452
if borrow_state & 0b_0000_1111 != 0b_0000_1111 {
442453
return Err(ProgramError::AccountBorrowFailed);
443454
}
@@ -610,11 +621,17 @@ impl AccountInfo {
610621
}
611622
}
612623

613-
/// Bytes to shift to get to the borrow state of lamports.
614-
const LAMPORTS_SHIFT: u8 = 4;
624+
/// Number of bits of the [`Account::borrow_state`] flag to shift to get to
625+
/// the borrow state bits for lamports.
626+
/// - `7 6 5 4 3 2 1 0`
627+
/// - `x x x x . . . .`
628+
const LAMPORTS_BORROW_SHIFT: u8 = 4;
615629

616-
/// Bytes to shift to get to the borrow state of data.
617-
const DATA_SHIFT: u8 = 0;
630+
/// Number of bits of the [`Account::borrow_state`] flag to shift to get to
631+
/// the borrow state bits for account data.
632+
/// - `7 6 5 4 3 2 1 0`
633+
/// - `. . . . x x x x`
634+
const DATA_BORROW_SHIFT: u8 = 0;
618635

619636
/// Reference to account data or lamports with checked borrow rules.
620637
pub struct Ref<'a, T: ?Sized> {
@@ -682,18 +699,18 @@ impl<T: ?Sized> Drop for Ref<'_, T> {
682699
}
683700

684701
/// Mask representing the mutable borrow flag for lamports.
685-
const LAMPORTS_MASK: u8 = 0b_1000_0000;
702+
const LAMPORTS_MUTABLE_BORROW_BITMASK: u8 = 0b_1000_0000;
686703

687704
/// Mask representing the mutable borrow flag for data.
688-
const DATA_MASK: u8 = 0b_0000_1000;
705+
const DATA_MUTABLE_BORROW_BITMASK: u8 = 0b_0000_1000;
689706

690707
/// Mutable reference to account data or lamports with checked borrow rules.
691708
pub struct RefMut<'a, T: ?Sized> {
692709
value: NonNull<T>,
693710
state: NonNull<u8>,
694-
/// Indicates the type of borrow (lamports or data) by representing the
695-
/// mutable borrow mask.
696-
borrow_mask: u8,
711+
/// Indicates borrowed field (lamports or data) by storing the bitmask
712+
/// representing the mutable borrow.
713+
borrow_bitmask: u8,
697714
/// The `value` raw pointer is only valid while the `&'a T` lives so we claim
698715
/// to hold a reference to it.
699716
marker: PhantomData<&'a mut T>,
@@ -712,7 +729,7 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
712729
RefMut {
713730
value: NonNull::from(f(&mut *orig)),
714731
state: orig.state,
715-
borrow_mask: orig.borrow_mask,
732+
borrow_bitmask: orig.borrow_bitmask,
716733
marker: PhantomData,
717734
}
718735
}
@@ -732,7 +749,7 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
732749
Ok(RefMut {
733750
value,
734751
state: orig.state,
735-
borrow_mask: orig.borrow_mask,
752+
borrow_bitmask: orig.borrow_bitmask,
736753
marker: PhantomData,
737754
})
738755
}
@@ -756,7 +773,7 @@ impl<T: ?Sized> core::ops::DerefMut for RefMut<'_, T> {
756773
impl<T: ?Sized> Drop for RefMut<'_, T> {
757774
fn drop(&mut self) {
758775
// unset the mutable borrow flag
759-
unsafe { *self.state.as_mut() |= self.borrow_mask };
776+
unsafe { *self.state.as_mut() |= self.borrow_bitmask };
760777
}
761778
}
762779

@@ -771,31 +788,31 @@ mod tests {
771788
#[test]
772789
fn test_data_ref() {
773790
let data: [u8; 4] = [0, 1, 2, 3];
774-
let mut state = NOT_BORROWED - (1 << DATA_SHIFT);
791+
let mut state = NOT_BORROWED - (1 << DATA_BORROW_SHIFT);
775792

776793
let ref_data = Ref {
777794
value: NonNull::from(&data),
778-
borrow_shift: DATA_SHIFT,
795+
borrow_shift: DATA_BORROW_SHIFT,
779796
// borrow state must be a mutable reference
780797
state: NonNull::from(&mut state),
781798
marker: PhantomData,
782799
};
783800

784801
let new_ref = Ref::map(ref_data, |data| &data[1]);
785802

786-
assert_eq!(state, NOT_BORROWED - (1 << DATA_SHIFT));
803+
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
787804
assert_eq!(*new_ref, 1);
788805

789806
let Ok(new_ref) = Ref::filter_map(new_ref, |_| Some(&3)) else {
790807
unreachable!()
791808
};
792809

793-
assert_eq!(state, NOT_BORROWED - (1 << DATA_SHIFT));
810+
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
794811
assert_eq!(*new_ref, 3);
795812

796813
let new_ref = Ref::filter_map(new_ref, |_| Option::<&u8>::None);
797814

798-
assert_eq!(state, NOT_BORROWED - (1 << DATA_SHIFT));
815+
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
799816
assert!(new_ref.is_err());
800817

801818
drop(new_ref);
@@ -806,31 +823,31 @@ mod tests {
806823
#[test]
807824
fn test_lamports_ref() {
808825
let lamports: u64 = 10000;
809-
let mut state = NOT_BORROWED - (1 << LAMPORTS_SHIFT);
826+
let mut state = NOT_BORROWED - (1 << LAMPORTS_BORROW_SHIFT);
810827

811828
let ref_lamports = Ref {
812829
value: NonNull::from(&lamports),
813-
borrow_shift: LAMPORTS_SHIFT,
830+
borrow_shift: LAMPORTS_BORROW_SHIFT,
814831
// borrow state must be a mutable reference
815832
state: NonNull::from(&mut state),
816833
marker: PhantomData,
817834
};
818835

819836
let new_ref = Ref::map(ref_lamports, |_| &1000);
820837

821-
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_SHIFT));
838+
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_BORROW_SHIFT));
822839
assert_eq!(*new_ref, 1000);
823840

824841
let Ok(new_ref) = Ref::filter_map(new_ref, |_| Some(&2000)) else {
825842
unreachable!()
826843
};
827844

828-
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_SHIFT));
845+
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_BORROW_SHIFT));
829846
assert_eq!(*new_ref, 2000);
830847

831848
let new_ref = Ref::filter_map(new_ref, |_| Option::<&i32>::None);
832849

833-
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_SHIFT));
850+
assert_eq!(state, NOT_BORROWED - (1 << LAMPORTS_BORROW_SHIFT));
834851
assert!(new_ref.is_err());
835852

836853
drop(new_ref);
@@ -845,7 +862,7 @@ mod tests {
845862

846863
let ref_data = RefMut {
847864
value: NonNull::from(&mut data),
848-
borrow_mask: DATA_MASK,
865+
borrow_bitmask: DATA_MUTABLE_BORROW_BITMASK,
849866
// borrow state must be a mutable reference
850867
state: NonNull::from(&mut state),
851868
marker: PhantomData,
@@ -873,7 +890,7 @@ mod tests {
873890

874891
let ref_lamports = RefMut {
875892
value: NonNull::from(&mut lamports),
876-
borrow_mask: LAMPORTS_MASK,
893+
borrow_bitmask: LAMPORTS_MUTABLE_BORROW_BITMASK,
877894
// borrow state must be a mutable reference
878895
state: NonNull::from(&mut state),
879896
marker: PhantomData,

sdk/pinocchio/src/instruction.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,35 @@ pub struct Account<'a> {
7373
_account_info: PhantomData<&'a AccountInfo>,
7474
}
7575

76+
/// Return a pointer to a type `U` given type `T` has a field of type `U` at the specified
77+
/// offset (in bytes) from the start of the `T` type.
78+
///
79+
/// # Safety
80+
///
81+
/// The caller must ensure that the `ptr` is a valid pointer to a type `T`, and `ptr + offset`
82+
/// points to bytes that are properly aligned for `U` and represent a bit pattern that is a
83+
/// valid instance of `U`.
84+
///
85+
/// If any of this requirements is not valid, this function leads to undefined behavior.
7686
#[inline(always)]
77-
const fn offset<T, U>(ptr: *const T, offset: usize) -> *const U {
87+
const unsafe fn field_at_offset<T, U>(ptr: *const T, offset: usize) -> *const U {
88+
// SAFETY: The caller ensures that the offset is valid for the type `T` and that
89+
// the resulting pointer is valid for type `U`.
7890
unsafe { (ptr as *const u8).add(offset) as *const U }
7991
}
8092

8193
impl<'a> From<&'a AccountInfo> for Account<'a> {
8294
fn from(account: &'a AccountInfo) -> Self {
8395
Account {
84-
key: offset(account.raw, 8),
85-
lamports: offset(account.raw, 72),
96+
// SAFETY: offset `8` is the `key` field in the `Account` struct.
97+
key: unsafe { field_at_offset(account.raw, 8) },
98+
// SAFETY: offset `72` is the `lamports` field in the `Account` struct.
99+
lamports: unsafe { field_at_offset(account.raw, 72) },
86100
data_len: account.data_len() as u64,
87-
data: offset(account.raw, 88),
88-
owner: offset(account.raw, 40),
101+
// SAFETY: offset `88` is the start of the account data in the `Account` struct.
102+
data: unsafe { field_at_offset(account.raw, 88) },
103+
// SAFETY: offset `40` is the `owner` field in the `Account` struct.
104+
owner: unsafe { field_at_offset(account.raw, 40) },
89105
// The `rent_epoch` field is not present in the `AccountInfo` struct,
90106
// since the value occurs after the variable data of the account in
91107
// the runtime input data.

0 commit comments

Comments
 (0)