@@ -3,44 +3,79 @@ use std::mem::variant_count;
33
44use crate :: * ;
55
6- /// A Windows `HANDLE` that represents a resource instead of being null or a pseudohandle.
7- ///
8- /// This is a seperate type from [`Handle`] to simplify the packing and unpacking code.
9- #[ derive( Clone , Copy ) ]
10- enum RealHandle {
11- Thread ( ThreadId ) ,
6+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
7+ pub enum PseudoHandle {
8+ CurrentThread ,
129}
1310
14- impl RealHandle {
15- const USABLE_BITS : u32 = 31 ;
11+ impl PseudoHandle {
12+ const CURRENT_THREAD_VALUE : u32 = 0 ;
1613
17- const THREAD_DISCRIMINANT : u32 = 1 ;
14+ fn value ( self ) -> u32 {
15+ match self {
16+ Self :: CurrentThread => Self :: CURRENT_THREAD_VALUE ,
17+ }
18+ }
19+
20+ fn from_value ( value : u32 ) -> Option < Self > {
21+ match value {
22+ Self :: CURRENT_THREAD_VALUE => Some ( Self :: CurrentThread ) ,
23+ _ => None ,
24+ }
25+ }
26+ }
27+
28+ /// Miri representation of a Windows `HANDLE`
29+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
30+ pub enum Handle {
31+ Null ,
32+ Pseudo ( PseudoHandle ) ,
33+ Thread ( ThreadId ) ,
34+ }
35+
36+ impl Handle {
37+ const NULL_DISCRIMINANT : u32 = 0 ;
38+ const PSEUDO_DISCRIMINANT : u32 = 1 ;
39+ const THREAD_DISCRIMINANT : u32 = 2 ;
1840
1941 fn discriminant ( self ) -> u32 {
2042 match self {
21- // can't use zero here because all zero handle is invalid
43+ Self :: Null => Self :: NULL_DISCRIMINANT ,
44+ Self :: Pseudo ( _) => Self :: PSEUDO_DISCRIMINANT ,
2245 Self :: Thread ( _) => Self :: THREAD_DISCRIMINANT ,
2346 }
2447 }
2548
2649 fn data ( self ) -> u32 {
2750 match self {
51+ Self :: Null => 0 ,
52+ Self :: Pseudo ( pseudo_handle) => pseudo_handle. value ( ) ,
2853 Self :: Thread ( thread) => thread. to_u32 ( ) ,
2954 }
3055 }
3156
3257 fn packed_disc_size ( ) -> u32 {
33- // log2(x) + 1 is how many bits it takes to store x
34- // because the discriminants start at 1, the variant count is equal to the highest discriminant
35- variant_count :: < Self > ( ) . ilog2 ( ) + 1
58+ // ceil(log2(x)) is how many bits it takes to store x numbers
59+ let variant_count = variant_count :: < Self > ( ) ;
60+
61+ // however, std's ilog2 is floor(log2(x))
62+ let floor_log2 = variant_count. ilog2 ( ) ;
63+
64+ // we need to add one for non powers of two to compensate for the difference
65+ let ceil_log2 = if variant_count. is_power_of_two ( ) { floor_log2 } else { floor_log2 + 1 } ;
66+
67+ ceil_log2
3668 }
3769
38- /// This function packs the discriminant and data values into a 31-bit space.
70+ /// Converts a handle into its machine representation.
71+ ///
72+ /// The upper [`Self::packed_disc_size()`] bits are used to store a discriminant corresponding to the handle variant.
73+ /// The remaining bits are used for the variant's field.
74+ ///
3975 /// None of this layout is guaranteed to applications by Windows or Miri.
40- /// The sign bit is not used to avoid overlapping any pseudo-handles.
41- fn to_packed ( self ) -> i32 {
76+ fn to_packed ( self ) -> u32 {
4277 let disc_size = Self :: packed_disc_size ( ) ;
43- let data_size = Self :: USABLE_BITS - disc_size;
78+ let data_size = u32 :: BITS - disc_size;
4479
4580 let discriminant = self . discriminant ( ) ;
4681 let data = self . data ( ) ;
@@ -53,90 +88,54 @@ impl RealHandle {
5388
5489 // packs the data into the lower `data_size` bits
5590 // and packs the discriminant right above the data
56- ( discriminant << data_size | data) as i32
91+ discriminant << data_size | data
5792 }
5893
5994 fn new ( discriminant : u32 , data : u32 ) -> Option < Self > {
6095 match discriminant {
96+ Self :: NULL_DISCRIMINANT if data == 0 => Some ( Self :: Null ) ,
97+ Self :: PSEUDO_DISCRIMINANT => Some ( Self :: Pseudo ( PseudoHandle :: from_value ( data) ?) ) ,
6198 Self :: THREAD_DISCRIMINANT => Some ( Self :: Thread ( data. into ( ) ) ) ,
6299 _ => None ,
63100 }
64101 }
65102
66103 /// see docs for `to_packed`
67- fn from_packed ( handle : i32 ) -> Option < Self > {
68- let handle_bits = handle as u32 ;
69-
104+ fn from_packed ( handle : u32 ) -> Option < Self > {
70105 let disc_size = Self :: packed_disc_size ( ) ;
71- let data_size = Self :: USABLE_BITS - disc_size;
106+ let data_size = u32 :: BITS - disc_size;
72107
73108 // the lower `data_size` bits of this mask are 1
74109 let data_mask = 2u32 . pow ( data_size) - 1 ;
75110
76111 // the discriminant is stored right above the lower `data_size` bits
77- let discriminant = handle_bits >> data_size;
112+ let discriminant = handle >> data_size;
78113
79114 // the data is stored in the lower `data_size` bits
80- let data = handle_bits & data_mask;
115+ let data = handle & data_mask;
81116
82117 Self :: new ( discriminant, data)
83118 }
84- }
85-
86- /// Miri representation of a Windows `HANDLE`
87- #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
88- pub enum Handle {
89- Null , // = 0
90-
91- // pseudo-handles
92- // The lowest real windows pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values
93- CurrentThread , // = -7
94-
95- // real handles
96- Thread ( ThreadId ) ,
97- }
98-
99- impl Handle {
100- const CURRENT_THREAD_VALUE : i32 = -7 ;
101-
102- fn to_packed ( self ) -> i32 {
103- match self {
104- Self :: Null => 0 ,
105- Self :: CurrentThread => Self :: CURRENT_THREAD_VALUE ,
106- Self :: Thread ( thread) => RealHandle :: Thread ( thread) . to_packed ( ) ,
107- }
108- }
109119
110120 pub fn to_scalar ( self , cx : & impl HasDataLayout ) -> Scalar < Provenance > {
111121 // 64-bit handles are sign extended 32-bit handles
112122 // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
113- let handle = self . to_packed ( ) . into ( ) ;
114-
115- Scalar :: from_machine_isize ( handle, cx)
116- }
117-
118- fn from_packed ( handle : i64 ) -> Option < Self > {
119- let current_thread_val = Self :: CURRENT_THREAD_VALUE as i64 ;
120-
121- if handle == 0 {
122- Some ( Self :: Null )
123- } else if handle == current_thread_val {
124- Some ( Self :: CurrentThread )
125- } else if let Ok ( handle) = handle. try_into ( ) {
126- match RealHandle :: from_packed ( handle) ? {
127- RealHandle :: Thread ( id) => Some ( Self :: Thread ( id) ) ,
128- }
129- } else {
130- // if a handle doesn't fit in an i32, it isn't valid.
131- None
132- }
123+ let signed_handle = self . to_packed ( ) as i32 ;
124+ Scalar :: from_machine_isize ( signed_handle. into ( ) , cx)
133125 }
134126
135127 pub fn from_scalar < ' tcx > (
136128 handle : Scalar < Provenance > ,
137129 cx : & impl HasDataLayout ,
138130 ) -> InterpResult < ' tcx , Option < Self > > {
139- let handle = handle. to_machine_isize ( cx) ?;
131+ let sign_extended_handle = handle. to_machine_isize ( cx) ?;
132+
133+ let handle = if let Ok ( signed_handle) = i32:: try_from ( sign_extended_handle) {
134+ signed_handle as u32
135+ } else {
136+ // if a handle doesn't fit in an i32, it isn't valid.
137+ return Ok ( None ) ;
138+ } ;
140139
141140 Ok ( Self :: from_packed ( handle) )
142141 }
0 commit comments