Skip to main content

fidl_next_codec/wire/fuchsia/
handle.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::fmt;
6use core::mem::{MaybeUninit, forget};
7
8use fidl_constants::{ALLOC_ABSENT_U32, ALLOC_PRESENT_U32};
9use zx::sys::{ZX_HANDLE_INVALID, zx_handle_t};
10
11use crate::fuchsia::{HandleDecoder, HandleEncoder};
12use crate::{
13    Constrained, Decode, DecodeError, Encode, EncodeError, EncodeOption, FromWire, FromWireOption,
14    IntoNatural, Slot, ValidationError, Wire, munge, wire,
15};
16
17/// TODO(https://fxbug.dev/465766514): remove
18pub type NullableHandle = Handle;
19
20/// A Zircon handle.
21#[repr(C, align(4))]
22pub union Handle {
23    encoded: wire::Uint32,
24    decoded: zx_handle_t,
25}
26
27impl Drop for Handle {
28    fn drop(&mut self) {
29        // SAFETY: `WireHandle` is always a valid `Handle`.
30        let handle = unsafe { zx::NullableHandle::from_raw(self.as_raw_handle()) };
31        drop(handle);
32    }
33}
34
35// TODO: validate handle rights
36impl Constrained for Handle {
37    type Constraint = ();
38
39    fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
40        Ok(())
41    }
42}
43
44// SAFETY: `Handle` is a union of `Uint32` and `zx_handle_t`, both of which are 4 bytes.
45// It has a stable layout and no padding.
46unsafe impl Wire for Handle {
47    type Narrowed<'de> = Self;
48
49    #[inline]
50    fn zero_padding(_: &mut MaybeUninit<Self>) {
51        // Wire handles have no padding
52    }
53}
54
55impl Handle {
56    /// Encodes a handle as present in an output.
57    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
58        // SAFETY: `out` is a valid mutable reference to a `MaybeUninit<Handle>`.
59        // Destructuring it via `munge!` only projects a pointer to `MaybeUninit<Uint32>`
60        // and does not read uninitialized memory.
61        let encoded = unsafe {
62            munge!(let Self { encoded } = out);
63            encoded
64        };
65        encoded.write(wire::Uint32(ALLOC_PRESENT_U32));
66    }
67
68    /// Returns whether the underlying `zx_handle_t` is invalid.
69    pub fn is_invalid(&self) -> bool {
70        self.as_raw_handle() == ZX_HANDLE_INVALID
71    }
72
73    /// Returns the underlying [`zx_handle_t`].
74    #[inline]
75    pub fn as_raw_handle(&self) -> zx_handle_t {
76        // SAFETY: `Handle` is a union of `Uint32` and `zx_handle_t`. Reading `decoded` is safe
77        // because both union fields are 4-byte integers (or wrappers thereof) and do not have
78        // invalid bit patterns.
79        unsafe { self.decoded }
80    }
81}
82
83impl fmt::Debug for Handle {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        self.as_raw_handle().fmt(f)
86    }
87}
88
89// SAFETY: If `decode` returns `Ok`, `slot` is guaranteed to contain a valid decoded `Handle`
90// because it has been written with a handle taken from the decoder.
91unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for Handle {
92    fn decode(
93        mut slot: Slot<'_, Self>,
94        decoder: &mut D,
95        _constraint: Self::Constraint,
96    ) -> Result<(), DecodeError> {
97        // SAFETY: `slot` is a valid `Slot` of `Handle`. Both `encoded` and `decoded` are
98        // 4-byte integer types with no invalid bit patterns.
99        let encoded = unsafe {
100            munge!(let Self { encoded } = slot.as_mut());
101            encoded
102        };
103
104        match **encoded {
105            ALLOC_ABSENT_U32 => return Err(DecodeError::RequiredHandleAbsent),
106            ALLOC_PRESENT_U32 => {
107                let handle = decoder.take_raw_handle()?;
108                // SAFETY: `slot` is a valid `Slot` of `Handle`. Destructuring it via `munge!`
109                // to write `decoded` is safe.
110                let mut decoded = unsafe {
111                    munge!(let Self { decoded } = slot);
112                    decoded
113                };
114                decoded.write(handle);
115            }
116            e => return Err(DecodeError::InvalidHandlePresence(e)),
117        }
118        Ok(())
119    }
120}
121
122/// TODO(https://fxbug.dev/465766514): remove
123pub type OptionalNullableHandle = OptionalHandle;
124
125/// An optional Zircon handle.
126#[derive(Debug)]
127#[repr(transparent)]
128pub struct OptionalHandle {
129    handle: Handle,
130}
131
132// TODO: validate handle rights
133impl Constrained for OptionalHandle {
134    type Constraint = ();
135
136    fn validate(_: Slot<'_, Self>, _: Self::Constraint) -> Result<(), ValidationError> {
137        Ok(())
138    }
139}
140
141// SAFETY: `OptionalHandle` is a transparent wrapper around `Handle`, which is `Wire`.
142unsafe impl Wire for OptionalHandle {
143    type Narrowed<'de> = Self;
144
145    #[inline]
146    fn zero_padding(out: &mut MaybeUninit<Self>) {
147        munge!(let Self { handle } = out);
148        Handle::zero_padding(handle);
149    }
150}
151
152impl OptionalHandle {
153    /// Encodes a handle as present in a slot.
154    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
155        munge!(let Self { handle } = out);
156        Handle::set_encoded_present(handle);
157    }
158
159    /// Encodes a handle as absent in an output.
160    pub fn set_encoded_absent(out: &mut MaybeUninit<Self>) {
161        // SAFETY: `out` is a valid mutable reference to a `MaybeUninit<OptionalHandle>`.
162        // Destructuring it via `munge!` only projects a pointer to `MaybeUninit<Uint32>`
163        // and does not read uninitialized memory.
164        let encoded = unsafe {
165            munge!(let Self { handle: Handle { encoded } } = out);
166            encoded
167        };
168        encoded.write(wire::Uint32(ZX_HANDLE_INVALID));
169    }
170
171    /// Returns whether a handle is present.
172    pub fn is_some(&self) -> bool {
173        !self.handle.is_invalid()
174    }
175
176    /// Returns whether a handle is absent.
177    pub fn is_none(&self) -> bool {
178        self.handle.is_invalid()
179    }
180
181    /// Returns the underlying [`zx_handle_t`], if any.
182    #[inline]
183    pub fn as_raw_handle(&self) -> Option<zx_handle_t> {
184        self.is_some().then(|| self.handle.as_raw_handle())
185    }
186}
187
188// SAFETY: If `decode` returns `Ok`, `slot` is guaranteed to contain a valid decoded
189// `OptionalHandle` because it is either left as `ALLOC_ABSENT_U32` (representing `None`) or
190// written with a handle taken from the decoder.
191unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for OptionalHandle {
192    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D, _: ()) -> Result<(), DecodeError> {
193        munge!(let Self { handle: mut wire_handle } = slot.as_mut());
194        // SAFETY: `wire_handle` is a valid `Slot` of `Handle`. Both `encoded` and `decoded` are
195        // 4-byte integer types with no invalid bit patterns.
196        let encoded = unsafe {
197            munge!(let Handle { encoded } = wire_handle.as_mut());
198            encoded
199        };
200
201        match **encoded {
202            ALLOC_ABSENT_U32 => (),
203            ALLOC_PRESENT_U32 => {
204                let handle = decoder.take_raw_handle()?;
205                // SAFETY: `wire_handle` is a valid `Slot` of `Handle`. Destructuring it via
206                // `munge!` to write `decoded` is safe.
207                let mut decoded = unsafe {
208                    munge!(let Handle { decoded } = wire_handle);
209                    decoded
210                };
211                decoded.write(handle);
212            }
213            e => return Err(DecodeError::InvalidHandlePresence(e)),
214        }
215        Ok(())
216    }
217}
218
219// SAFETY: `Handle` has no padding, and `encode` initializes the entire 4 bytes of `out`
220// by calling `Handle::set_encoded_present`.
221unsafe impl<E: HandleEncoder + ?Sized> Encode<Handle, E> for zx::NullableHandle {
222    fn encode(
223        self,
224        encoder: &mut E,
225        out: &mut MaybeUninit<Handle>,
226        _constraint: (),
227    ) -> Result<(), EncodeError> {
228        if self.is_invalid() {
229            Err(EncodeError::InvalidRequiredHandle)
230        } else {
231            encoder.push_handle(self)?;
232            Handle::set_encoded_present(out);
233            Ok(())
234        }
235    }
236}
237
238impl FromWire<Handle> for zx::NullableHandle {
239    fn from_wire(wire: Handle) -> Self {
240        // SAFETY: `WireHandle` is always a valid `NullableHandle`.
241        let handle = unsafe { zx::NullableHandle::from_raw(wire.as_raw_handle()) };
242        forget(wire);
243        handle
244    }
245}
246
247impl IntoNatural for Handle {
248    type Natural = zx::NullableHandle;
249}
250
251// SAFETY: `OptionalHandle` has no padding, and `encode_option` initializes the entire 4 bytes
252// of `out` by calling either `set_encoded_present` or `set_encoded_absent`.
253unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<OptionalHandle, E> for zx::NullableHandle {
254    fn encode_option(
255        this: Option<Self>,
256        encoder: &mut E,
257        out: &mut MaybeUninit<OptionalHandle>,
258        _constraint: (),
259    ) -> Result<(), EncodeError> {
260        if let Some(handle) = this {
261            encoder.push_handle(handle)?;
262            OptionalHandle::set_encoded_present(out);
263        } else {
264            OptionalHandle::set_encoded_absent(out);
265        }
266        Ok(())
267    }
268}
269
270impl FromWireOption<OptionalHandle> for zx::NullableHandle {
271    fn from_wire_option(wire: OptionalHandle) -> Option<Self> {
272        let raw_handle = wire.as_raw_handle();
273        forget(wire);
274        // SAFETY: `raw` is a valid handle value from a decoded `OptionalHandle`.
275        // We `forget(wire)` above to prevent double-closing the handle.
276        raw_handle.map(|raw| unsafe { zx::NullableHandle::from_raw(raw) })
277    }
278}
279
280impl IntoNatural for OptionalHandle {
281    type Natural = Option<zx::NullableHandle>;
282}