gidl_util/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! This crate contains utility functions used in GIDL tests and benchmarks.
use fidl::encoding::{Context, Decode, Decoder, DefaultFuchsiaResourceDialect, TypeMarker};
use fidl::{AsHandleRef, Handle, HandleBased, HandleDisposition, HandleInfo, HandleOp, Rights};
use zx_status::Status;
use zx_types;
/// Handle subtypes that can be created via `create_handles`. Each subtype `X`
/// corresponds to a `fidl::X` type that implements `HandleBased`.
pub enum HandleSubtype {
Event,
Channel,
}
impl HandleSubtype {
fn obj_type(&self) -> zx_types::zx_obj_type_t {
match self {
HandleSubtype::Event => zx_types::ZX_OBJ_TYPE_EVENT,
HandleSubtype::Channel => zx_types::ZX_OBJ_TYPE_CHANNEL,
}
}
}
/// Specifies a handle to be created with `create_handles`. Corresponds to
/// `HandleDef` in //tools/fidl/gidl/ir/test_case.go.
pub struct HandleDef {
pub subtype: HandleSubtype,
pub rights: Rights,
}
/// Creates a vector of raw handles based on `defs`. Panics if creating any of
/// the handles fails. The caller is responsible for closing the handles.
pub fn create_handles(defs: &[HandleDef]) -> Vec<zx_types::zx_handle_info_t> {
let mut factory: HandleFactory = Default::default();
let mut handle_infos = Vec::with_capacity(defs.len());
for def in defs {
let default_rights_handle = match def.subtype {
HandleSubtype::Event => factory.create_event().unwrap().into_handle(),
HandleSubtype::Channel => factory.create_channel().unwrap().into_handle(),
};
handle_infos.push(zx_types::zx_handle_info_t {
handle: match def.rights {
Rights::SAME_RIGHTS => default_rights_handle,
rights => default_rights_handle.replace(rights).unwrap(),
}
.into_raw(),
ty: def.subtype.obj_type(),
rights: def.rights.bits(),
unused: 0,
});
}
handle_infos
}
/// HandleFactory creates handles. For handle subtypes that come in pairs, it
/// stores the second one and returns it on the next call to minimize syscalls.
#[derive(Default)]
struct HandleFactory {
extra_channel: Option<fidl::Channel>,
}
// See src/lib/fuchsia-async/src/handle/mod.rs for handle subtypes. The ones
// marked "Everywhere" are fully emulated on non-Fuchsia, so we can define
// factory functions that work on all platforms.
impl HandleFactory {
fn create_event(&mut self) -> Result<fidl::Event, Status> {
Ok(fidl::Event::create())
}
fn create_channel(&mut self) -> Result<fidl::Channel, Status> {
match self.extra_channel.take() {
Some(channel) => Ok(channel),
None => {
let (c1, c2) = fidl::Channel::create();
self.extra_channel = Some(c2);
Ok(c1)
}
}
}
}
/// Copies a raw handle into an owned `HandleBased` handle.
pub fn copy_handle<T: HandleBased>(handle_info: &zx_types::zx_handle_info_t) -> T {
// Safety: The `from_raw` method is only unsafe because it can lead to
// handles being double-closed if used incorrectly. GIDL-generated code
// ensures that handles are only closed once.
T::from_handle(unsafe { Handle::from_raw(handle_info.handle) })
}
/// Copies raw handles from the given indices to a new vector.
pub fn select_raw_handle_infos(
handle_defs: &[zx_types::zx_handle_info_t],
indices: &[usize],
) -> Vec<zx_types::zx_handle_info_t> {
indices.iter().map(|&i| handle_defs[i]).collect()
}
/// Copies raw handles from the given indices to a new vector of owned
/// `HandleInfo`s. The caller must ensure handles are closed exactly once.
pub fn select_handle_infos(
handle_defs: &[zx_types::zx_handle_info_t],
indices: &[usize],
) -> Vec<HandleInfo> {
// Safety: The `from_raw` method is only unsafe because it can lead to
// handles being double-closed if used incorrectly. GIDL-generated code
// ensures that handles are only closed once.
indices.iter().map(|&i| unsafe { HandleInfo::from_raw(handle_defs[i]) }).collect()
}
/// Gets the koid of a handle from its raw handle info. Panics if the
/// `zx_object_get_info` syscall fails.
pub fn get_handle_koid(handle_info: &zx_types::zx_handle_info_t) -> zx_types::zx_koid_t {
// Safety: The `from_raw` method is only unsafe because it can lead to
// handles being double-closed if used incorrectly. We wrap it in
// ManuallyDrop to prevent closing the handle.
let handle = std::mem::ManuallyDrop::new(unsafe { Handle::from_raw(handle_info.handle) });
handle.basic_info().unwrap().koid.raw_koid()
}
/// Converts a `HandleDisposition` to a raw `zx_handle_disposition_t`.
pub fn to_zx_handle_disposition_t(
mut hd: HandleDisposition<'_>,
) -> zx_types::zx_handle_disposition_t {
match hd.take_op() {
HandleOp::Move(handle) => zx_types::zx_handle_disposition_t {
operation: zx_types::ZX_HANDLE_OP_MOVE,
handle: handle.raw_handle(),
type_: hd.object_type.into_raw(),
rights: hd.rights.bits(),
result: hd.result.into_raw(),
},
HandleOp::Duplicate(handle_ref) => zx_types::zx_handle_disposition_t {
operation: zx_types::ZX_HANDLE_OP_DUPLICATE,
handle: handle_ref.raw_handle(),
type_: hd.object_type.into_raw(),
rights: hd.rights.bits(),
result: hd.result.into_raw(),
},
}
}
/// Returns the result of the `zx_object_get_info` syscall with topic
/// `ZX_INFO_HANDLE_VALID`. In particular, returns `Status::BAD_HANDLE` if
/// the handle is dangling because it was already closed or never assigned
/// to the process in the first place.
///
/// This should only be used in a single-threaded process immediately after
/// a handle is created/closed, since "The kernel is free to re-use the
/// integer values of closed handles for newly created objects".
/// https://fuchsia.dev/fuchsia-src/concepts/kernel/handles#invalid_handles_and_handle_reuse
#[cfg(target_os = "fuchsia")]
pub fn get_info_handle_valid(handle_info: &zx_types::zx_handle_info_t) -> Result<(), Status> {
use zx::sys;
Status::ok(unsafe {
sys::zx_object_get_info(
handle_info.handle,
sys::ZX_INFO_HANDLE_VALID,
std::ptr::null_mut(),
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
)
})
}
#[cfg(not(target_os = "fuchsia"))]
pub fn get_info_handle_valid(handle_info: &zx_types::zx_handle_info_t) -> Result<(), Status> {
use fidl::EmulatedHandleRef;
// Safety: The `from_raw` method is only unsafe because it can lead to
// handles being double-closed if used incorrectly. We wrap it in
// ManuallyDrop to prevent closing the handle.
let handle = std::mem::ManuallyDrop::new(unsafe { Handle::from_raw(handle_info.handle) });
// Match the behavior of the syscall, returning BAD_HANDLE if the handle is
// the special "never a valid handle" ZX_HANDLE_INVALID, or if it is invalid
// because it was closed or never assigned in the first place (dangling).
if handle.is_invalid() || handle.is_dangling() {
Err(Status::BAD_HANDLE)
} else {
Ok(())
}
}
/// Returns a vector of `value` repeated `len` times.
pub fn repeat<T: Clone>(value: T, len: usize) -> Vec<T> {
std::iter::repeat(value).take(len).collect::<Vec<_>>()
}
/// Decodes `T` from the given bytes and handles. Panics on failure.
pub fn decode_value<T: TypeMarker>(
context: Context,
bytes: &[u8],
handles: &mut [HandleInfo],
) -> T::Owned
where
T::Owned: Decode<T, DefaultFuchsiaResourceDialect>,
{
let mut value = T::Owned::new_empty();
Decoder::decode_with_context::<T>(context, bytes, handles, &mut value).expect(
"failed decoding for the GIDL decode() function (not a regular decode test failure!)",
);
value
}