@@ -995,62 +995,94 @@ mod tests {
995
995
}
996
996
997
997
// the old bpf_loader in-program deserializer bpf_loader::id()
998
- #[ allow ( clippy :: type_complexity ) ]
998
+ #[ deny ( unsafe_op_in_unsafe_fn ) ]
999
999
pub unsafe fn deserialize_unaligned < ' a > (
1000
1000
input : * mut u8 ,
1001
1001
) -> ( & ' a Pubkey , Vec < AccountInfo < ' a > > , & ' a [ u8 ] ) {
1002
+ // this boring boilerplate struct is needed until inline const...
1003
+ struct Ptr < T > ( std:: marker:: PhantomData < T > ) ;
1004
+ impl < T > Ptr < T > {
1005
+ const COULD_BE_UNALIGNED : bool = std:: mem:: align_of :: < T > ( ) > 1 ;
1006
+
1007
+ #[ inline( always) ]
1008
+ fn read_possibly_unaligned ( input : * mut u8 , offset : usize ) -> T {
1009
+ unsafe {
1010
+ let src = input. add ( offset) as * const T ;
1011
+ if Self :: COULD_BE_UNALIGNED {
1012
+ src. read_unaligned ( )
1013
+ } else {
1014
+ src. read ( )
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ // rustc inserts debug_assert! for misaligned pointer dereferences when
1020
+ // deserializing, starting from [1]. so, use std::mem::transmute as the last resort
1021
+ // while preventing clippy from complaining to suggest not to use it.
1022
+ // [1]: https://github.com/rust-lang/rust/commit/22a7a19f9333bc1fcba97ce444a3515cb5fb33e6
1023
+ // as for the ub nature of the misaligned pointer dereference, this is
1024
+ // acceptable in this code, given that this is cfg(test) and it's cared only with
1025
+ // x86-64 and the target only incurs some performance penalty, not like segfaults
1026
+ // in other targets.
1027
+ #[ inline( always) ]
1028
+ fn ref_possibly_unaligned < ' a > ( input : * mut u8 , offset : usize ) -> & ' a T {
1029
+ #[ allow( clippy:: transmute_ptr_to_ref) ]
1030
+ unsafe {
1031
+ transmute ( input. add ( offset) as * const T )
1032
+ }
1033
+ }
1034
+
1035
+ // See ref_possibly_unaligned's comment
1036
+ #[ inline( always) ]
1037
+ fn mut_possibly_unaligned < ' a > ( input : * mut u8 , offset : usize ) -> & ' a mut T {
1038
+ #[ allow( clippy:: transmute_ptr_to_ref) ]
1039
+ unsafe {
1040
+ transmute ( input. add ( offset) as * mut T )
1041
+ }
1042
+ }
1043
+ }
1044
+
1002
1045
let mut offset: usize = 0 ;
1003
1046
1004
1047
// number of accounts present
1005
1048
1006
- let num_accounts = ( input. add ( offset ) as * const u64 ) . read_unaligned ( ) as usize ;
1049
+ let num_accounts = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset ) as usize ;
1007
1050
offset += size_of :: < u64 > ( ) ;
1008
1051
1009
1052
// account Infos
1010
1053
1011
1054
let mut accounts = Vec :: with_capacity ( num_accounts) ;
1012
1055
for _ in 0 ..num_accounts {
1013
- let dup_info = * ( input. add ( offset ) as * const u8 ) ;
1056
+ let dup_info = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset ) ;
1014
1057
offset += size_of :: < u8 > ( ) ;
1015
1058
if dup_info == NON_DUP_MARKER {
1016
- let is_signer = ( input. add ( offset ) as * const u8 ) . read_unaligned ( ) != 0 ;
1059
+ let is_signer = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset ) != 0 ;
1017
1060
offset += size_of :: < u8 > ( ) ;
1018
1061
1019
- let is_writable = ( input. add ( offset ) as * const u8 ) . read_unaligned ( ) != 0 ;
1062
+ let is_writable = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset ) != 0 ;
1020
1063
offset += size_of :: < u8 > ( ) ;
1021
1064
1022
- let key: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1065
+ let key = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1023
1066
offset += size_of :: < Pubkey > ( ) ;
1024
1067
1025
- let lamports = Rc :: new ( RefCell :: new ( {
1026
- // rustc started to insert debug_assert! for misaligned pointer dereference,
1027
- // starting from [1]. so, use std::mem::transmute as the last resort while
1028
- // preventing clippy from complaining to suggest not to use it.
1029
- // [1]: https://github.com/rust-lang/rust/commit/22a7a19f9333bc1fcba97ce444a3515cb5fb33e6
1030
- // as for the ub nature itself in the misaligned pointer dereference, this is
1031
- // acceptable given that this is cfg(test) code and we're only cared with
1032
- // x86-64 and the target only incurs some perf. penalty, not like segfaults in
1033
- // other targets.
1034
- #[ allow( clippy:: transmute_ptr_to_ref) ]
1035
- transmute ( input. add ( offset) )
1036
- } ) ) ;
1068
+ let lamports = Rc :: new ( RefCell :: new ( Ptr :: mut_possibly_unaligned ( input, offset) ) ) ;
1037
1069
offset += size_of :: < u64 > ( ) ;
1038
1070
1039
- let data_len = ( input. add ( offset ) as * const u64 ) . read_unaligned ( ) as usize ;
1071
+ let data_len = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset ) as usize ;
1040
1072
offset += size_of :: < u64 > ( ) ;
1041
1073
1042
- let data = Rc :: new ( RefCell :: new ( {
1074
+ let data = Rc :: new ( RefCell :: new ( unsafe {
1043
1075
from_raw_parts_mut ( input. add ( offset) , data_len)
1044
1076
} ) ) ;
1045
1077
offset += data_len;
1046
1078
1047
- let owner: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1079
+ let owner: & Pubkey = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1048
1080
offset += size_of :: < Pubkey > ( ) ;
1049
1081
1050
- let executable = ( input. add ( offset ) as * const u8 ) . read_unaligned ( ) != 0 ;
1082
+ let executable = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset ) != 0 ;
1051
1083
offset += size_of :: < u8 > ( ) ;
1052
1084
1053
- let rent_epoch = ( input. add ( offset ) as * const u64 ) . read_unaligned ( ) ;
1085
+ let rent_epoch = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset ) ;
1054
1086
offset += size_of :: < u64 > ( ) ;
1055
1087
1056
1088
accounts. push ( AccountInfo {
@@ -1071,15 +1103,15 @@ mod tests {
1071
1103
1072
1104
// instruction data
1073
1105
1074
- let instruction_data_len = ( input. add ( offset ) as * const u64 ) . read_unaligned ( ) as usize ;
1106
+ let instruction_data_len = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset ) as usize ;
1075
1107
offset += size_of :: < u64 > ( ) ;
1076
1108
1077
- let instruction_data = { from_raw_parts ( input. add ( offset) , instruction_data_len) } ;
1109
+ let instruction_data = unsafe { from_raw_parts ( input. add ( offset) , instruction_data_len) } ;
1078
1110
offset += instruction_data_len;
1079
1111
1080
1112
// program Id
1081
1113
1082
- let program_id: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1114
+ let program_id = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1083
1115
1084
1116
( program_id, accounts, instruction_data)
1085
1117
}
0 commit comments