@@ -12,37 +12,42 @@ enum RealHandle {
1212}
1313
1414impl RealHandle {
15- fn discriminant ( self ) -> u64 {
15+ const USABLE_BITS : u32 = 31 ;
16+
17+ fn discriminant ( self ) -> u32 {
1618 match self {
1719 // can't use zero here because all zero handle is invalid
1820 Self :: Thread ( _) => 1 ,
1921 }
2022 }
2123
22- fn data ( self ) -> u64 {
24+ fn data ( self ) -> u32 {
2325 match self {
24- Self :: Thread ( thread) => thread. to_u32 ( ) as u64 ,
26+ Self :: Thread ( thread) => thread. to_u32 ( ) ,
2527 }
2628 }
2729
28- fn packed_disc_size ( ) -> u64 {
29- ( variant_count :: < Self > ( ) . log2 ( ) + 1 ) as u64
30+ fn packed_disc_size ( ) -> u32 {
31+ ( variant_count :: < Self > ( ) . log2 ( ) + 1 )
32+ . try_into ( )
33+ . expect ( "this would require more than 2^4294967294 variants to overflow" )
3034 }
3135
32- fn to_packed ( self , bits : u64 ) -> u64 {
33- // top bit and lower 2 bits need to be clear
34- let usable_bits = ( bits - 3 ) . min ( 32 ) ;
35-
36+ /// This function packs the discriminant and data values into a 31-bit space.
37+ /// None of this layout is guaranteed to applications by Windows or Miri.
38+ /// The sign bit is not used to avoid overlapping any pseudo-handles.
39+ fn to_packed ( self ) -> i32 {
3640 let disc_size = Self :: packed_disc_size ( ) ;
37- let data_size = usable_bits - disc_size;
41+ let data_size = Self :: USABLE_BITS - disc_size;
3842
3943 let discriminant = self . discriminant ( ) ;
4044 let data = self . data ( ) ;
4145
42- assert ! ( discriminant < 2u64 . pow( disc_size as u32 ) ) ;
43- assert ! ( data < 2u64 . pow( data_size as u32 ) ) ;
46+ // these assertions ensure the components avoid overlapping eachother and the sign bit
47+ assert ! ( discriminant < 2u32 . pow( disc_size) ) ;
48+ assert ! ( data < 2u32 . pow( data_size) ) ;
4449
45- ( discriminant << data_size | data) << 2
50+ ( discriminant << data_size | data) as i32
4651 }
4752
4853 fn new ( discriminant : u32 , data : u32 ) -> Option < Self > {
@@ -52,67 +57,74 @@ impl RealHandle {
5257 }
5358 }
5459
55- fn from_packed ( handle : u64 , bits : u64 ) -> Option < Self > {
56- let usable_bits = ( bits - 3 ) . min ( 32 ) ;
60+ /// see docs for `to_packed`
61+ fn from_packed ( handle : i32 ) -> Option < Self > {
62+ let handle_bits = handle as u32 ;
5763
5864 let disc_size = Self :: packed_disc_size ( ) ;
59- let data_size = usable_bits - disc_size;
60- let data_mask = 2u64 . pow ( data_size as u32 ) - 1 ;
65+ let data_size = Self :: USABLE_BITS - disc_size;
66+
67+ // the lower `data_size` bits of this mask are 1
68+ let data_mask = 2u32 . pow ( data_size) - 1 ;
6169
62- let discriminant = handle >> data_size >> 2 ;
63- let data = handle >> 2 & data_mask;
70+ let discriminant = handle_bits >> data_size;
71+ let data = handle_bits & data_mask;
6472
65- Self :: new ( discriminant. try_into ( ) . unwrap ( ) , data. try_into ( ) . unwrap ( ) )
73+ Self :: new ( discriminant, data)
6674 }
6775}
6876
6977/// Miri representation of a Windows `HANDLE`
7078#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
7179pub enum Handle {
7280 Null , // = 0
81+
7382 // pseudo-handles
74- CurrentThread , // = -2
83+ // The lowest pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values
84+ CurrentThread , // = -7
85+
7586 // real handles
7687 Thread ( ThreadId ) ,
7788}
7889
7990impl Handle {
80- fn to_packed ( self , bits : u64 ) -> i64 {
91+ fn to_packed ( self ) -> i32 {
8192 match self {
8293 Self :: Null => 0 ,
83- Self :: CurrentThread => -2 ,
84- Self :: Thread ( thread) => RealHandle :: Thread ( thread) . to_packed ( bits ) as i64 ,
94+ Self :: CurrentThread => -7 ,
95+ Self :: Thread ( thread) => RealHandle :: Thread ( thread) . to_packed ( ) ,
8596 }
8697 }
8798
8899 pub fn to_scalar ( self , cx : & impl HasDataLayout ) -> Scalar < Tag > {
89- let bits = cx . data_layout ( ) . pointer_size . bits ( ) ;
90-
91- let handle = self . to_packed ( bits ) ;
100+ // 64-bit handles are sign extended 32-bit handles
101+ // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
102+ let handle = self . to_packed ( ) . into ( ) ;
92103
93104 Scalar :: from_machine_isize ( handle, cx)
94105 }
95106
96- fn from_packed ( handle : i64 , bits : u64 ) -> Option < Self > {
107+ fn from_packed ( handle : i64 ) -> Option < Self > {
97108 if handle == 0 {
98109 Some ( Self :: Null )
99- } else if handle == -2 {
110+ } else if handle == -7 {
100111 Some ( Self :: CurrentThread )
101- } else {
102- match RealHandle :: from_packed ( handle as u64 , bits ) ? {
112+ } else if let Ok ( handle ) = handle . try_into ( ) {
113+ match RealHandle :: from_packed ( handle) ? {
103114 RealHandle :: Thread ( id) => Some ( Self :: Thread ( id) ) ,
104115 }
116+ } else {
117+ // if a handle doesn't fit in an i32, it isn't valid.
118+ None
105119 }
106120 }
107121
108122 pub fn from_scalar < ' tcx > (
109123 handle : Scalar < Tag > ,
110124 cx : & impl HasDataLayout ,
111125 ) -> InterpResult < ' tcx , Option < Self > > {
112- let bits = cx. data_layout ( ) . pointer_size . bits ( ) ;
113-
114126 let handle = handle. to_machine_isize ( cx) ?;
115127
116- Ok ( Self :: from_packed ( handle, bits ) )
128+ Ok ( Self :: from_packed ( handle) )
117129 }
118130}
0 commit comments