@@ -14,7 +14,8 @@ use std::ops::RangeFrom;
1414use std:: os:: raw;
1515use std:: os:: windows:: prelude:: * ;
1616
17- pub struct RegistryKey ( Repr ) ;
17+ /// Must never be `HKEY_PERFORMANCE_DATA`.
18+ pub ( crate ) struct RegistryKey ( Repr ) ;
1819
1920type HKEY = * mut u8 ;
2021type DWORD = u32 ;
@@ -29,7 +30,8 @@ type REGSAM = u32;
2930
3031const ERROR_SUCCESS : DWORD = 0 ;
3132const 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 ;
3335const REG_SZ : DWORD = 1 ;
3436const KEY_READ : DWORD = 0x20019 ;
3537const KEY_WOW64_32KEY : DWORD = 0x200 ;
@@ -66,8 +68,11 @@ extern "system" {
6668
6769struct OwnedKey ( HKEY ) ;
6870
71+ /// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys.
6972enum Repr {
70- Const ( HKEY ) ,
73+ /// `HKEY_LOCAL_MACHINE`.
74+ LocalMachine ,
75+ /// A subkey of `HKEY_LOCAL_MACHINE`.
7176 Owned ( OwnedKey ) ,
7277}
7378
@@ -79,16 +84,17 @@ pub struct Iter<'a> {
7984unsafe impl Sync for Repr { }
8085unsafe impl Send for Repr { }
8186
82- pub static LOCAL_MACHINE : RegistryKey = RegistryKey ( Repr :: Const ( HKEY_LOCAL_MACHINE ) ) ;
87+ pub ( crate ) const LOCAL_MACHINE : RegistryKey = RegistryKey ( Repr :: LocalMachine ) ;
8388
8489impl RegistryKey {
8590 fn raw ( & self ) -> HKEY {
8691 match self . 0 {
87- Repr :: Const ( val ) => val ,
92+ Repr :: LocalMachine => HKEY_LOCAL_MACHINE ,
8893 Repr :: Owned ( ref val) => val. 0 ,
8994 }
9095 }
9196
97+ /// Open a sub-key of `self`.
9298 pub fn open ( & self , key : & OsStr ) -> io:: Result < RegistryKey > {
9399 let key = key. encode_wide ( ) . chain ( Some ( 0 ) ) . collect :: < Vec < _ > > ( ) ;
94100 let mut ret = 0 as * mut _ ;
@@ -140,9 +146,13 @@ impl RegistryKey {
140146 }
141147
142148 // 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
144150 // 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] ;
146156 let err = RegQueryValueExW (
147157 self . raw ( ) ,
148158 name. as_ptr ( ) ,
@@ -151,17 +161,34 @@ impl RegistryKey {
151161 v. as_mut_ptr ( ) as * mut _ ,
152162 & mut len,
153163 ) ;
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.
154168 if err != ERROR_SUCCESS as LONG {
155169 return Err ( io:: Error :: from_raw_os_error ( err as i32 ) ) ;
156170 }
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) ;
159186 // Some registry keys may have a terminating nul character, but
160187 // 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 {
162189 v. pop ( ) ;
163190 }
164- Ok ( OsString :: from_wide ( & v) )
191+ return Ok ( OsString :: from_wide ( & v) ) ;
165192 }
166193 }
167194}
0 commit comments