Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/windows/descriptor.rs
5394 views
1
// Copyright 2022 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::convert::TryFrom;
6
use std::fs::File;
7
use std::io::Stderr;
8
use std::io::Stdin;
9
use std::io::Stdout;
10
use std::marker::Send;
11
use std::marker::Sync;
12
use std::ops::Drop;
13
use std::os::windows::io::AsRawHandle;
14
use std::os::windows::io::FromRawHandle;
15
use std::os::windows::io::IntoRawHandle;
16
use std::os::windows::io::RawHandle;
17
use std::sync::OnceLock;
18
19
use win_util::duplicate_handle;
20
use win_util::win32_wide_string;
21
use winapi::shared::minwindef::BOOL;
22
use winapi::shared::minwindef::TRUE;
23
use winapi::um::handleapi::CloseHandle;
24
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
25
use winapi::um::libloaderapi::GetProcAddress;
26
use winapi::um::libloaderapi::LoadLibraryW;
27
28
use super::Result;
29
use crate::descriptor::AsRawDescriptor;
30
use crate::descriptor::Descriptor;
31
use crate::descriptor::FromRawDescriptor;
32
use crate::descriptor::IntoRawDescriptor;
33
use crate::descriptor::SafeDescriptor;
34
35
pub type RawDescriptor = RawHandle;
36
37
pub const INVALID_DESCRIPTOR: RawDescriptor = INVALID_HANDLE_VALUE;
38
39
impl PartialEq for SafeDescriptor {
40
fn eq(&self, other: &Self) -> bool {
41
compare_object_handles(self.descriptor, other.as_raw_descriptor())
42
}
43
}
44
45
impl Drop for SafeDescriptor {
46
fn drop(&mut self) {
47
// SAFETY: trivially safe
48
unsafe { CloseHandle(self.descriptor) };
49
}
50
}
51
52
impl AsRawHandle for SafeDescriptor {
53
fn as_raw_handle(&self) -> RawHandle {
54
self.as_raw_descriptor()
55
}
56
}
57
58
type CompareObjectHandlesFn = extern "system" fn(RawHandle, RawHandle) -> BOOL;
59
60
static COMPARE_OBJECT_HANDLES: OnceLock<CompareObjectHandlesFn> = OnceLock::new();
61
62
fn init_compare_object_handles() -> CompareObjectHandlesFn {
63
// SAFETY: the return value is checked.
64
let handle = unsafe { LoadLibraryW(win32_wide_string("Kernelbase").as_ptr()) };
65
if handle.is_null() {
66
return compare_object_handles_fallback;
67
}
68
69
// SAFETY: the return value is checked.
70
let symbol = unsafe { GetProcAddress(handle, c"CompareObjectHandles".as_ptr()) };
71
if symbol.is_null() {
72
return compare_object_handles_fallback;
73
}
74
75
// SAFETY: trivially safe
76
unsafe {
77
std::mem::transmute::<*mut winapi::shared::minwindef::__some_function, CompareObjectHandlesFn>(
78
symbol,
79
)
80
}
81
}
82
83
// This function is only used if CompareObjectHandles() is not available.
84
extern "system" fn compare_object_handles_fallback(first: RawHandle, second: RawHandle) -> BOOL {
85
(first == second).into()
86
}
87
88
fn compare_object_handles(first: RawHandle, second: RawHandle) -> bool {
89
let func = COMPARE_OBJECT_HANDLES.get_or_init(init_compare_object_handles);
90
let ret = func(first, second);
91
ret == TRUE
92
}
93
94
impl TryFrom<&dyn AsRawHandle> for SafeDescriptor {
95
type Error = std::io::Error;
96
97
fn try_from(handle: &dyn AsRawHandle) -> std::result::Result<Self, Self::Error> {
98
Ok(SafeDescriptor {
99
descriptor: duplicate_handle(handle.as_raw_handle())?,
100
})
101
}
102
}
103
104
impl SafeDescriptor {
105
/// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
106
/// share the same underlying count within the kernel.
107
pub fn try_clone(&self) -> Result<SafeDescriptor> {
108
// SAFETY:
109
// Safe because `duplicate_handle` will return a valid handle, or at the very least error
110
// out.
111
Ok(unsafe {
112
SafeDescriptor::from_raw_descriptor(win_util::duplicate_handle(self.descriptor)?)
113
})
114
}
115
}
116
117
// SAFETY:
118
// On Windows, RawHandles are represented by raw pointers but are not used as such in
119
// rust code, and are therefore safe to send between threads.
120
unsafe impl Send for SafeDescriptor {}
121
// SAFETY: See comments for impl Send
122
unsafe impl Sync for SafeDescriptor {}
123
124
// SAFETY:
125
// On Windows, RawHandles are represented by raw pointers but are opaque to the
126
// userspace and cannot be derefenced by rust code, and are therefore safe to
127
// send between threads.
128
unsafe impl Send for Descriptor {}
129
// SAFETY: See comments for impl Send
130
unsafe impl Sync for Descriptor {}
131
132
macro_rules! AsRawDescriptor {
133
($name:ident) => {
134
impl AsRawDescriptor for $name {
135
fn as_raw_descriptor(&self) -> RawDescriptor {
136
return self.as_raw_handle();
137
}
138
}
139
};
140
}
141
142
macro_rules! FromRawDescriptor {
143
($name:ident) => {
144
impl FromRawDescriptor for $name {
145
// SAFETY: It is caller's responsibility to ensure that the descriptor is valid.
146
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
147
return $name::from_raw_handle(descriptor);
148
}
149
}
150
};
151
}
152
153
macro_rules! IntoRawDescriptor {
154
($name:ident) => {
155
impl IntoRawDescriptor for $name {
156
fn into_raw_descriptor(self) -> RawDescriptor {
157
return self.into_raw_handle();
158
}
159
}
160
};
161
}
162
163
// Implementations for File. This enables the File-type to use the cross-platform
164
// RawDescriptor, but does not mean File should be used as a generic
165
// descriptor container. That should go to either SafeDescriptor or another more
166
// relevant container type.
167
// TODO(b/148971445): Ensure there are no usages of File that aren't actually files.
168
AsRawDescriptor!(File);
169
FromRawDescriptor!(File);
170
IntoRawDescriptor!(File);
171
AsRawDescriptor!(Stdin);
172
AsRawDescriptor!(Stdout);
173
AsRawDescriptor!(Stderr);
174
175
#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
176
#[test]
177
#[allow(clippy::eq_op)]
178
fn clone_equality() {
179
use crate::descriptor::IntoRawDescriptor;
180
use crate::Event;
181
182
let evt = Event::new().unwrap();
183
// SAFETY: Given evt is created above and is valid.
184
let descriptor = unsafe { SafeDescriptor::from_raw_descriptor(evt.into_raw_descriptor()) };
185
186
assert_eq!(descriptor, descriptor);
187
188
assert_eq!(
189
descriptor,
190
descriptor.try_clone().expect("failed to clone event")
191
);
192
193
let evt2 = Event::new().unwrap();
194
// SAFETY: Given evt2 is created above and is valid.
195
let another = unsafe { SafeDescriptor::from_raw_descriptor(evt2.into_raw_descriptor()) };
196
197
assert_ne!(descriptor, another);
198
}
199
200