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