@@ -563,6 +563,7 @@ mod tests {
563
563
} ,
564
564
std:: {
565
565
cell:: RefCell ,
566
+ mem:: transmute,
566
567
rc:: Rc ,
567
568
slice:: { self , from_raw_parts, from_raw_parts_mut} ,
568
569
} ,
@@ -994,58 +995,94 @@ mod tests {
994
995
}
995
996
996
997
// the old bpf_loader in-program deserializer bpf_loader::id()
997
- #[ allow ( clippy :: type_complexity ) ]
998
+ #[ deny ( unsafe_op_in_unsafe_fn ) ]
998
999
pub unsafe fn deserialize_unaligned < ' a > (
999
1000
input : * mut u8 ,
1000
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
+
1001
1045
let mut offset: usize = 0 ;
1002
1046
1003
1047
// number of accounts present
1004
1048
1005
- #[ allow( clippy:: cast_ptr_alignment) ]
1006
- let num_accounts = * ( input. add ( offset) as * const u64 ) 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
- #[ allow( clippy:: cast_ptr_alignment) ]
1017
- let is_signer = * ( input. add ( offset) as * const u8 ) != 0 ;
1059
+ let is_signer = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset) != 0 ;
1018
1060
offset += size_of :: < u8 > ( ) ;
1019
1061
1020
- #[ allow( clippy:: cast_ptr_alignment) ]
1021
- let is_writable = * ( input. add ( offset) as * const u8 ) != 0 ;
1062
+ let is_writable = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset) != 0 ;
1022
1063
offset += size_of :: < u8 > ( ) ;
1023
1064
1024
- let key: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1065
+ let key = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1025
1066
offset += size_of :: < Pubkey > ( ) ;
1026
1067
1027
- #[ allow( clippy:: cast_ptr_alignment) ]
1028
- let lamports = Rc :: new ( RefCell :: new ( & mut * ( input. add ( offset) as * mut u64 ) ) ) ;
1068
+ let lamports = Rc :: new ( RefCell :: new ( Ptr :: mut_possibly_unaligned ( input, offset) ) ) ;
1029
1069
offset += size_of :: < u64 > ( ) ;
1030
1070
1031
- #[ allow( clippy:: cast_ptr_alignment) ]
1032
- let data_len = * ( input. add ( offset) as * const u64 ) as usize ;
1071
+ let data_len = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset) as usize ;
1033
1072
offset += size_of :: < u64 > ( ) ;
1034
1073
1035
- let data = Rc :: new ( RefCell :: new ( {
1074
+ let data = Rc :: new ( RefCell :: new ( unsafe {
1036
1075
from_raw_parts_mut ( input. add ( offset) , data_len)
1037
1076
} ) ) ;
1038
1077
offset += data_len;
1039
1078
1040
- let owner: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1079
+ let owner: & Pubkey = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1041
1080
offset += size_of :: < Pubkey > ( ) ;
1042
1081
1043
- #[ allow( clippy:: cast_ptr_alignment) ]
1044
- let executable = * ( input. add ( offset) as * const u8 ) != 0 ;
1082
+ let executable = Ptr :: < u8 > :: read_possibly_unaligned ( input, offset) != 0 ;
1045
1083
offset += size_of :: < u8 > ( ) ;
1046
1084
1047
- #[ allow( clippy:: cast_ptr_alignment) ]
1048
- let rent_epoch = * ( input. add ( offset) as * const u64 ) ;
1085
+ let rent_epoch = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset) ;
1049
1086
offset += size_of :: < u64 > ( ) ;
1050
1087
1051
1088
accounts. push ( AccountInfo {
@@ -1066,16 +1103,15 @@ mod tests {
1066
1103
1067
1104
// instruction data
1068
1105
1069
- #[ allow( clippy:: cast_ptr_alignment) ]
1070
- let instruction_data_len = * ( input. add ( offset) as * const u64 ) as usize ;
1106
+ let instruction_data_len = Ptr :: < u64 > :: read_possibly_unaligned ( input, offset) as usize ;
1071
1107
offset += size_of :: < u64 > ( ) ;
1072
1108
1073
- 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) } ;
1074
1110
offset += instruction_data_len;
1075
1111
1076
1112
// program Id
1077
1113
1078
- let program_id: & Pubkey = & * ( input. add ( offset ) as * const Pubkey ) ;
1114
+ let program_id = Ptr :: < Pubkey > :: ref_possibly_unaligned ( input, offset ) ;
1079
1115
1080
1116
( program_id, accounts, instruction_data)
1081
1117
}
0 commit comments