@@ -12,107 +12,151 @@ enum RealHandle {
1212}
1313
1414impl RealHandle {
15- fn discriminant ( self ) -> u64 {
15+ const USABLE_BITS : u32 = 31 ;
16+
17+ const THREAD_DISCRIMINANT : u32 = 1 ;
18+
19+ fn discriminant ( self ) -> u32 {
1620 match self {
1721 // can't use zero here because all zero handle is invalid
18- Self :: Thread ( _) => 1 ,
22+ Self :: Thread ( _) => Self :: THREAD_DISCRIMINANT ,
1923 }
2024 }
2125
22- fn data ( self ) -> u64 {
26+ fn data ( self ) -> u32 {
2327 match self {
24- Self :: Thread ( thread) => thread. to_u32 ( ) as u64 ,
28+ Self :: Thread ( thread) => thread. to_u32 ( ) ,
2529 }
2630 }
2731
28- fn packed_disc_size ( ) -> u64 {
29- ( variant_count :: < Self > ( ) . log2 ( ) + 1 ) as u64
32+ 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 > ( ) . log2 ( ) + 1
3036 }
3137
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-
38+ /// This function packs the discriminant and data values into a 31-bit space.
39+ /// 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 {
3642 let disc_size = Self :: packed_disc_size ( ) ;
37- let data_size = usable_bits - disc_size;
43+ let data_size = Self :: USABLE_BITS - disc_size;
3844
3945 let discriminant = self . discriminant ( ) ;
4046 let data = self . data ( ) ;
4147
42- assert ! ( discriminant < 2u64 . pow ( disc_size as u32 ) ) ;
43- assert ! ( data < 2u64 . pow( data_size as u32 ) ) ;
48+ // make sure the discriminant fits into ` disc_size` bits
49+ assert ! ( discriminant < 2u32 . pow( disc_size ) ) ;
4450
45- ( discriminant << data_size | data) << 2
51+ // make sure the data fits into `data_size` bits
52+ assert ! ( data < 2u32 . pow( data_size) ) ;
53+
54+ // packs the data into the lower `data_size` bits
55+ // and packs the discriminant right above the data
56+ ( discriminant << data_size | data) as i32
4657 }
4758
4859 fn new ( discriminant : u32 , data : u32 ) -> Option < Self > {
4960 match discriminant {
50- 1 => Some ( Self :: Thread ( data. into ( ) ) ) ,
61+ Self :: THREAD_DISCRIMINANT => Some ( Self :: Thread ( data. into ( ) ) ) ,
5162 _ => None ,
5263 }
5364 }
5465
55- fn from_packed ( handle : u64 , bits : u64 ) -> Option < Self > {
56- let usable_bits = ( bits - 3 ) . min ( 32 ) ;
66+ /// see docs for `to_packed`
67+ fn from_packed ( handle : i32 ) -> Option < Self > {
68+ let handle_bits = handle as u32 ;
5769
5870 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 ;
71+ let data_size = Self :: USABLE_BITS - disc_size;
72+
73+ // the lower `data_size` bits of this mask are 1
74+ let data_mask = 2u32 . pow ( data_size) - 1 ;
6175
62- let discriminant = handle >> data_size >> 2 ;
63- let data = handle >> 2 & data_mask ;
76+ // the discriminant is stored right above the lower `data_size` bits
77+ let discriminant = handle_bits >> data_size ;
6478
65- Self :: new ( discriminant. try_into ( ) . unwrap ( ) , data. try_into ( ) . unwrap ( ) )
79+ // the data is stored in the lower `data_size` bits
80+ let data = handle_bits & data_mask;
81+
82+ Self :: new ( discriminant, data)
6683 }
6784}
6885
6986/// Miri representation of a Windows `HANDLE`
7087#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
7188pub enum Handle {
7289 Null , // = 0
90+
7391 // pseudo-handles
74- CurrentThread , // = -2
92+ // The lowest pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values
93+ CurrentThread , // = -7
94+
7595 // real handles
7696 Thread ( ThreadId ) ,
7797}
7898
7999impl Handle {
80- fn to_packed ( self , bits : u64 ) -> i64 {
100+ const CURRENT_THREAD_VALUE : i32 = -7 ;
101+
102+ fn to_packed ( self ) -> i32 {
81103 match self {
82104 Self :: Null => 0 ,
83- Self :: CurrentThread => - 2 ,
84- Self :: Thread ( thread) => RealHandle :: Thread ( thread) . to_packed ( bits ) as i64 ,
105+ Self :: CurrentThread => Self :: CURRENT_THREAD_VALUE ,
106+ Self :: Thread ( thread) => RealHandle :: Thread ( thread) . to_packed ( ) ,
85107 }
86108 }
87109
88110 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 ) ;
111+ // 64-bit handles are sign extended 32-bit handles
112+ // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
113+ let handle = self . to_packed ( ) . into ( ) ;
92114
93115 Scalar :: from_machine_isize ( handle, cx)
94116 }
95117
96- fn from_packed ( handle : i64 , bits : u64 ) -> Option < Self > {
118+ fn from_packed ( handle : i64 ) -> Option < Self > {
119+ let current_thread_val = Self :: CURRENT_THREAD_VALUE as i64 ;
120+
97121 if handle == 0 {
98122 Some ( Self :: Null )
99- } else if handle == - 2 {
123+ } else if handle == current_thread_val {
100124 Some ( Self :: CurrentThread )
101- } else {
102- match RealHandle :: from_packed ( handle as u64 , bits ) ? {
125+ } else if let Ok ( handle ) = handle . try_into ( ) {
126+ match RealHandle :: from_packed ( handle) ? {
103127 RealHandle :: Thread ( id) => Some ( Self :: Thread ( id) ) ,
104128 }
129+ } else {
130+ // if a handle doesn't fit in an i32, it isn't valid.
131+ None
105132 }
106133 }
107134
108135 pub fn from_scalar < ' tcx > (
109136 handle : Scalar < Tag > ,
110137 cx : & impl HasDataLayout ,
111138 ) -> InterpResult < ' tcx , Option < Self > > {
112- let bits = cx. data_layout ( ) . pointer_size . bits ( ) ;
113-
114139 let handle = handle. to_machine_isize ( cx) ?;
115140
116- Ok ( Self :: from_packed ( handle, bits) )
141+ Ok ( Self :: from_packed ( handle) )
142+ }
143+ }
144+
145+ impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
146+
147+ #[ allow( non_snake_case) ]
148+ pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
149+ fn CloseHandle ( & mut self , handle_op : & OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
150+ let this = self . eval_context_mut ( ) ;
151+
152+ match Handle :: from_scalar ( this. read_scalar ( handle_op) ?. check_init ( ) ?, this) ? {
153+ Some ( Handle :: Thread ( thread) ) => this. detach_thread ( thread) ?,
154+ _ =>
155+ throw_machine_stop ! ( TerminationInfo :: Abort (
156+ "invalid handle passed to `CloseHandle`" . into( )
157+ ) ) ,
158+ } ;
159+
160+ Ok ( ( ) )
117161 }
118162}
0 commit comments