summaryrefslogtreecommitdiffstats
path: root/vendor/cc/src/registry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/cc/src/registry.rs')
-rw-r--r--vendor/cc/src/registry.rs53
1 files changed, 40 insertions, 13 deletions
diff --git a/vendor/cc/src/registry.rs b/vendor/cc/src/registry.rs
index 2ac2fa63b..cae32219c 100644
--- a/vendor/cc/src/registry.rs
+++ b/vendor/cc/src/registry.rs
@@ -3,8 +3,8 @@
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
@@ -14,7 +14,8 @@ use std::ops::RangeFrom;
use std::os::raw;
use std::os::windows::prelude::*;
-pub struct RegistryKey(Repr);
+/// Must never be `HKEY_PERFORMANCE_DATA`.
+pub(crate) struct RegistryKey(Repr);
type HKEY = *mut u8;
type DWORD = u32;
@@ -29,7 +30,8 @@ type REGSAM = u32;
const ERROR_SUCCESS: DWORD = 0;
const ERROR_NO_MORE_ITEMS: DWORD = 259;
-const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
+// Sign-extend into 64 bits if needed.
+const HKEY_LOCAL_MACHINE: HKEY = 0x80000002u32 as i32 as isize as HKEY;
const REG_SZ: DWORD = 1;
const KEY_READ: DWORD = 0x20019;
const KEY_WOW64_32KEY: DWORD = 0x200;
@@ -66,8 +68,11 @@ extern "system" {
struct OwnedKey(HKEY);
+/// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys.
enum Repr {
- Const(HKEY),
+ /// `HKEY_LOCAL_MACHINE`.
+ LocalMachine,
+ /// A subkey of `HKEY_LOCAL_MACHINE`.
Owned(OwnedKey),
}
@@ -79,16 +84,17 @@ pub struct Iter<'a> {
unsafe impl Sync for Repr {}
unsafe impl Send for Repr {}
-pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE));
+pub(crate) const LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::LocalMachine);
impl RegistryKey {
fn raw(&self) -> HKEY {
match self.0 {
- Repr::Const(val) => val,
+ Repr::LocalMachine => HKEY_LOCAL_MACHINE,
Repr::Owned(ref val) => val.0,
}
}
+ /// Open a sub-key of `self`.
pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
let mut ret = 0 as *mut _;
@@ -140,9 +146,13 @@ impl RegistryKey {
}
// The length here is the length in bytes, but we're using wide
- // characters so we need to be sure to halve it for the capacity
+ // characters so we need to be sure to halve it for the length
// passed in.
- let mut v = Vec::with_capacity(len as usize / 2);
+ assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
+ let vlen = len as usize / 2;
+ // Defensively initialized, see comment about
+ // `HKEY_PERFORMANCE_DATA` below.
+ let mut v = vec![0u16; vlen];
let err = RegQueryValueExW(
self.raw(),
name.as_ptr(),
@@ -151,17 +161,34 @@ impl RegistryKey {
v.as_mut_ptr() as *mut _,
&mut len,
);
+ // We don't check for `ERROR_MORE_DATA` (which would if the value
+ // grew between the first and second call to `RegQueryValueExW`),
+ // both because it's extremely unlikely, and this is a bit more
+ // defensive more defensive against weird types of registry keys.
if err != ERROR_SUCCESS as LONG {
return Err(io::Error::from_raw_os_error(err as i32));
}
- v.set_len(len as usize / 2);
-
+ // The length is allowed to change, but should still be even, as
+ // well as smaller.
+ assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
+ // If the length grew but returned a success code, it *probably*
+ // indicates we're `HKEY_PERFORMANCE_DATA` or a subkey(?). We
+ // consider this UB, since those keys write "undefined" or
+ // "unpredictable" values to len, and need to use a completely
+ // different loop structure. This should be impossible (and enforce
+ // it in the API to the best of our ability), but to mitigate the
+ // damage we do some smoke-checks on the len, and ensure `v` has
+ // been fully initialized (rather than trusting the result of
+ // `RegQueryValueExW`).
+ let actual_len = len as usize / 2;
+ assert!(actual_len <= v.len());
+ v.truncate(actual_len);
// Some registry keys may have a terminating nul character, but
// we're not interested in that, so chop it off if it's there.
- if v[v.len() - 1] == 0 {
+ if !v.is_empty() && v[v.len() - 1] == 0 {
v.pop();
}
- Ok(OsString::from_wide(&v))
+ return Ok(OsString::from_wide(&v));
}
}
}