@@ -14,7 +14,8 @@ use std::ops::RangeFrom;
14
14
use std:: os:: raw;
15
15
use std:: os:: windows:: prelude:: * ;
16
16
17
- pub struct RegistryKey ( Repr ) ;
17
+ /// Must never be `HKEY_PERFORMANCE_DATA`.
18
+ pub ( crate ) struct RegistryKey ( Repr ) ;
18
19
19
20
type HKEY = * mut u8 ;
20
21
type DWORD = u32 ;
@@ -29,7 +30,8 @@ type REGSAM = u32;
29
30
30
31
const ERROR_SUCCESS : DWORD = 0 ;
31
32
const ERROR_NO_MORE_ITEMS : DWORD = 259 ;
32
- const HKEY_LOCAL_MACHINE : HKEY = 0x80000002 as HKEY ;
33
+ // Sign-extend into 64 bits if needed.
34
+ const HKEY_LOCAL_MACHINE : HKEY = 0x80000002u32 as i32 as isize as HKEY ;
33
35
const REG_SZ : DWORD = 1 ;
34
36
const KEY_READ : DWORD = 0x20019 ;
35
37
const KEY_WOW64_32KEY : DWORD = 0x200 ;
@@ -66,8 +68,11 @@ extern "system" {
66
68
67
69
struct OwnedKey ( HKEY ) ;
68
70
71
+ /// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys.
69
72
enum Repr {
70
- Const ( HKEY ) ,
73
+ /// `HKEY_LOCAL_MACHINE`.
74
+ LocalMachine ,
75
+ /// A subkey of `HKEY_LOCAL_MACHINE`.
71
76
Owned ( OwnedKey ) ,
72
77
}
73
78
@@ -79,16 +84,17 @@ pub struct Iter<'a> {
79
84
unsafe impl Sync for Repr { }
80
85
unsafe impl Send for Repr { }
81
86
82
- pub static LOCAL_MACHINE : RegistryKey = RegistryKey ( Repr :: Const ( HKEY_LOCAL_MACHINE ) ) ;
87
+ pub ( crate ) const LOCAL_MACHINE : RegistryKey = RegistryKey ( Repr :: LocalMachine ) ;
83
88
84
89
impl RegistryKey {
85
90
fn raw ( & self ) -> HKEY {
86
91
match self . 0 {
87
- Repr :: Const ( val ) => val ,
92
+ Repr :: LocalMachine => HKEY_LOCAL_MACHINE ,
88
93
Repr :: Owned ( ref val) => val. 0 ,
89
94
}
90
95
}
91
96
97
+ /// Open a sub-key of `self`.
92
98
pub fn open ( & self , key : & OsStr ) -> io:: Result < RegistryKey > {
93
99
let key = key. encode_wide ( ) . chain ( Some ( 0 ) ) . collect :: < Vec < _ > > ( ) ;
94
100
let mut ret = 0 as * mut _ ;
@@ -140,9 +146,13 @@ impl RegistryKey {
140
146
}
141
147
142
148
// The length here is the length in bytes, but we're using wide
143
- // characters so we need to be sure to halve it for the capacity
149
+ // characters so we need to be sure to halve it for the length
144
150
// passed in.
145
- let mut v = Vec :: with_capacity ( len as usize / 2 ) ;
151
+ assert ! ( len % 2 == 0 , "impossible wide string size: {} bytes" , len) ;
152
+ let vlen = len as usize / 2 ;
153
+ // Defensively initialized, see comment about
154
+ // `HKEY_PERFORMANCE_DATA` below.
155
+ let mut v = vec ! [ 0u16 ; vlen] ;
146
156
let err = RegQueryValueExW (
147
157
self . raw ( ) ,
148
158
name. as_ptr ( ) ,
@@ -151,17 +161,34 @@ impl RegistryKey {
151
161
v. as_mut_ptr ( ) as * mut _ ,
152
162
& mut len,
153
163
) ;
164
+ // We don't check for `ERROR_MORE_DATA` (which would if the value
165
+ // grew between the first and second call to `RegQueryValueExW`),
166
+ // both because it's extremely unlikely, and this is a bit more
167
+ // defensive more defensive against weird types of registry keys.
154
168
if err != ERROR_SUCCESS as LONG {
155
169
return Err ( io:: Error :: from_raw_os_error ( err as i32 ) ) ;
156
170
}
157
- v. set_len ( len as usize / 2 ) ;
158
-
171
+ // The length is allowed to change, but should still be even, as
172
+ // well as smaller.
173
+ assert ! ( len % 2 == 0 , "impossible wide string size: {} bytes" , len) ;
174
+ // If the length grew but returned a success code, it *probably*
175
+ // indicates we're `HKEY_PERFORMANCE_DATA` or a subkey(?). We
176
+ // consider this UB, since those keys write "undefined" or
177
+ // "unpredictable" values to len, and need to use a completely
178
+ // different loop structure. This should be impossible (and enforce
179
+ // it in the API to the best of our ability), but to mitigate the
180
+ // damage we do some smoke-checks on the len, and ensure `v` has
181
+ // been fully initialized (rather than trusting the result of
182
+ // `RegQueryValueExW`).
183
+ let actual_len = len as usize / 2 ;
184
+ assert ! ( actual_len <= v. len( ) ) ;
185
+ v. truncate ( actual_len) ;
159
186
// Some registry keys may have a terminating nul character, but
160
187
// we're not interested in that, so chop it off if it's there.
161
- if v[ v. len ( ) - 1 ] == 0 {
188
+ if !v . is_empty ( ) && v[ v. len ( ) - 1 ] == 0 {
162
189
v. pop ( ) ;
163
190
}
164
- Ok ( OsString :: from_wide ( & v) )
191
+ return Ok ( OsString :: from_wide ( & v) ) ;
165
192
}
166
193
}
167
194
}
0 commit comments