Skip to content

Commit 911a049

Browse files
uefi: Improve support for null protocol interfaces
Modify `ScopedProtocol` to check if the interface pointer is null. If it is, then `Deref` and `DerefMut` will now panic. They are also now marked `#[track_caller]` so that the panic location points to the caller. Also added `get` and `get_mut` methods to get potentially-null interface data without panicking.
1 parent f6a5844 commit 911a049

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
- `DevicePathInstance::to_boxed`, `DevicePathInstance::to_owned`, and `DevicePathInstance::as_bytes`
88
- `DevicePathNode::data`
99
- Added `Event::from_ptr`, `Event::as_ptr`, and `Handle::as_ptr`.
10+
- Added `ScopedProtocol::get` and `ScopedProtocol::get_mut` to access
11+
potentially-null interfaces without panicking.
1012

1113
### Changed
1214
- Renamed `LoadImageSource::FromFilePath` to `LoadImageSource::FromDevicePath`
15+
- The `Deref` and `DerefMut` impls for `ScopedProtocol` will now panic if the
16+
interface pointer is null.
1317

1418
### Removed
1519

uefi/src/table/boot.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,10 +1338,13 @@ impl BootServices {
13381338
attributes as u32,
13391339
)
13401340
.to_result_with_val(|| {
1341-
let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell<P>;
1341+
let interface = (!interface.is_null()).then(|| {
1342+
let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell<P>;
1343+
&*interface
1344+
});
13421345

13431346
ScopedProtocol {
1344-
interface: &*interface,
1347+
interface,
13451348
open_params: params,
13461349
boot_services: self,
13471350
}
@@ -1814,12 +1817,23 @@ pub struct OpenProtocolParams {
18141817
/// An open protocol interface. Automatically closes the protocol
18151818
/// interface on drop.
18161819
///
1820+
/// Most protocols have interface data associated with them. `ScopedProtocol`
1821+
/// implements [`Deref`] and [`DerefMut`] to access this data. A few protocols
1822+
/// (such as [`DevicePath`] and [`LoadedImageDevicePath`]) may be installed with
1823+
/// null interface data, in which case [`Deref`] and [`DerefMut`] will
1824+
/// panic. The [`get`] and [`get_mut`] methods may be used to access the
1825+
/// optional interface data without panicking.
1826+
///
18171827
/// See also the [`BootServices`] documentation for details of how to open a
18181828
/// protocol and why [`UnsafeCell`] is used.
1829+
///
1830+
/// [`LoadedImageDevicePath`]: crate::proto::device_path::LoadedImageDevicePath
1831+
/// [`get`]: ScopedProtocol::get
1832+
/// [`get_mut`]: ScopedProtocol::get_mut
18191833
#[derive(Debug)]
18201834
pub struct ScopedProtocol<'a, P: Protocol + ?Sized> {
18211835
/// The protocol interface.
1822-
interface: &'a UnsafeCell<P>,
1836+
interface: Option<&'a UnsafeCell<P>>,
18231837

18241838
open_params: OpenProtocolParams,
18251839
boot_services: &'a BootServices,
@@ -1847,14 +1861,32 @@ impl<'a, P: Protocol + ?Sized> Drop for ScopedProtocol<'a, P> {
18471861
impl<'a, P: Protocol + ?Sized> Deref for ScopedProtocol<'a, P> {
18481862
type Target = P;
18491863

1864+
#[track_caller]
18501865
fn deref(&self) -> &Self::Target {
1851-
unsafe { &*self.interface.get() }
1866+
unsafe { &*self.interface.unwrap().get() }
18521867
}
18531868
}
18541869

18551870
impl<'a, P: Protocol + ?Sized> DerefMut for ScopedProtocol<'a, P> {
1871+
#[track_caller]
18561872
fn deref_mut(&mut self) -> &mut Self::Target {
1857-
unsafe { &mut *self.interface.get() }
1873+
unsafe { &mut *self.interface.unwrap().get() }
1874+
}
1875+
}
1876+
1877+
impl<'a, P: Protocol + ?Sized> ScopedProtocol<'a, P> {
1878+
/// Get the protocol interface data, or `None` if the open protocol's
1879+
/// interface is null.
1880+
#[must_use]
1881+
pub fn get(&self) -> Option<&P> {
1882+
self.interface.map(|p| unsafe { &*p.get() })
1883+
}
1884+
1885+
/// Get the protocol interface data, or `None` if the open protocol's
1886+
/// interface is null.
1887+
#[must_use]
1888+
pub fn get_mut(&self) -> Option<&mut P> {
1889+
self.interface.map(|p| unsafe { &mut *p.get() })
18581890
}
18591891
}
18601892

0 commit comments

Comments
 (0)