@@ -12,107 +12,151 @@ enum RealHandle {
12
12
}
13
13
14
14
impl 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 {
16
20
match self {
17
21
// can't use zero here because all zero handle is invalid
18
- Self :: Thread ( _) => 1 ,
22
+ Self :: Thread ( _) => Self :: THREAD_DISCRIMINANT ,
19
23
}
20
24
}
21
25
22
- fn data ( self ) -> u64 {
26
+ fn data ( self ) -> u32 {
23
27
match self {
24
- Self :: Thread ( thread) => thread. to_u32 ( ) as u64 ,
28
+ Self :: Thread ( thread) => thread. to_u32 ( ) ,
25
29
}
26
30
}
27
31
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
30
36
}
31
37
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 {
36
42
let disc_size = Self :: packed_disc_size ( ) ;
37
- let data_size = usable_bits - disc_size;
43
+ let data_size = Self :: USABLE_BITS - disc_size;
38
44
39
45
let discriminant = self . discriminant ( ) ;
40
46
let data = self . data ( ) ;
41
47
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 ) ) ;
44
50
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
46
57
}
47
58
48
59
fn new ( discriminant : u32 , data : u32 ) -> Option < Self > {
49
60
match discriminant {
50
- 1 => Some ( Self :: Thread ( data. into ( ) ) ) ,
61
+ Self :: THREAD_DISCRIMINANT => Some ( Self :: Thread ( data. into ( ) ) ) ,
51
62
_ => None ,
52
63
}
53
64
}
54
65
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 ;
57
69
58
70
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 ;
61
75
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 ;
64
78
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)
66
83
}
67
84
}
68
85
69
86
/// Miri representation of a Windows `HANDLE`
70
87
#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
71
88
pub enum Handle {
72
89
Null , // = 0
90
+
73
91
// 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
+
75
95
// real handles
76
96
Thread ( ThreadId ) ,
77
97
}
78
98
79
99
impl Handle {
80
- fn to_packed ( self , bits : u64 ) -> i64 {
100
+ const CURRENT_THREAD_VALUE : i32 = -7 ;
101
+
102
+ fn to_packed ( self ) -> i32 {
81
103
match self {
82
104
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 ( ) ,
85
107
}
86
108
}
87
109
88
110
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 ( ) ;
92
114
93
115
Scalar :: from_machine_isize ( handle, cx)
94
116
}
95
117
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
+
97
121
if handle == 0 {
98
122
Some ( Self :: Null )
99
- } else if handle == - 2 {
123
+ } else if handle == current_thread_val {
100
124
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) ? {
103
127
RealHandle :: Thread ( id) => Some ( Self :: Thread ( id) ) ,
104
128
}
129
+ } else {
130
+ // if a handle doesn't fit in an i32, it isn't valid.
131
+ None
105
132
}
106
133
}
107
134
108
135
pub fn from_scalar < ' tcx > (
109
136
handle : Scalar < Tag > ,
110
137
cx : & impl HasDataLayout ,
111
138
) -> InterpResult < ' tcx , Option < Self > > {
112
- let bits = cx. data_layout ( ) . pointer_size . bits ( ) ;
113
-
114
139
let handle = handle. to_machine_isize ( cx) ?;
115
140
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 ( ( ) )
117
161
}
118
162
}
0 commit comments