Skip to content

Commit 25e2105

Browse files
authored
Merge pull request #1988 from rust-osdev/safetycomments
treewide: enforce safety comments
2 parents 93e94fa + bb6067c commit 25e2105

79 files changed

Lines changed: 893 additions & 59 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

uefi-raw/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
#![deny(
1616
clippy::all,
1717
clippy::missing_const_for_fn,
18+
clippy::missing_safety_doc,
1819
clippy::must_use_candidate,
1920
clippy::ptr_as_ptr,
21+
clippy::undocumented_unsafe_blocks,
2022
clippy::use_self,
2123
missing_debug_implementations,
2224
unused

uefi-raw/src/net.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,15 @@ mod tests {
321321
fn test_ip_addr_conversion() {
322322
let core_addr = core::net::IpAddr::V4(core::net::Ipv4Addr::from(TEST_IPV4));
323323
let uefi_addr = IpAddress::from(core_addr);
324-
assert_eq!(unsafe { uefi_addr.v4.0 }, TEST_IPV4);
324+
// SAFETY: `IpAddress::from` constructed the IPv4 variant above.
325+
let octets = unsafe { uefi_addr.v4.0 };
326+
assert_eq!(octets, TEST_IPV4);
325327

326328
let core_addr = core::net::IpAddr::V6(core::net::Ipv6Addr::from(TEST_IPV6));
327329
let uefi_addr = IpAddress::from(core_addr);
328-
assert_eq!(unsafe { uefi_addr.v6.0 }, TEST_IPV6);
330+
// SAFETY: `IpAddress::from` constructed the IPv6 variant above.
331+
let octets = unsafe { uefi_addr.v6.0 };
332+
assert_eq!(octets, TEST_IPV6);
329333
}
330334

331335
/// Test conversions between `MacAddress` and octet arrays.
@@ -373,40 +377,42 @@ mod tests {
373377
let octets = [0_u8, 1, 2, 3];
374378
assert_eq!(Ipv4Address::from(octets), Ipv4Address(octets));
375379
let uefi_addr = IpAddress::from(octets);
380+
// SAFETY: `from([u8; 4])` constructs the IPv4 variant.
376381
assert_eq!(&octets, &unsafe { uefi_addr.v4.octets() });
377382
}
378383
// octets -> Ipv6Address
379384
{
380385
let octets = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
381386
assert_eq!(Ipv6Address::from(octets), Ipv6Address(octets));
382387
let uefi_addr = IpAddress::from(octets);
388+
// SAFETY: `from([u8; 16])` constructs the IPv6 variant.
383389
assert_eq!(&octets, &unsafe { uefi_addr.v6.octets() });
384390
}
385391
// StdIpv4Addr -> Ipv4Address
386392
{
387393
let octets = [7, 5, 3, 1];
388394
let core_ipv4_addr = core::net::Ipv4Addr::from(octets);
389395
assert_eq!(Ipv4Address::from(core_ipv4_addr).octets(), octets);
390-
assert_eq!(
391-
unsafe { IpAddress::from(core_ipv4_addr).v4.octets() },
392-
octets
393-
);
396+
// SAFETY: The `Ipv4Addr` conversion selects the IPv4 variant.
397+
let converted = unsafe { IpAddress::from(core_ipv4_addr).v4.octets() };
398+
assert_eq!(converted, octets);
394399
}
395400
// StdIpv6Addr -> Ipv6Address
396401
{
397402
let octets = [7, 5, 3, 1, 6, 3, 8, 5, 2, 5, 2, 7, 3, 5, 2, 6];
398403
let core_ipv6_addr = core::net::Ipv6Addr::from(octets);
399404
assert_eq!(Ipv6Address::from(core_ipv6_addr).octets(), octets);
400-
assert_eq!(
401-
unsafe { IpAddress::from(core_ipv6_addr).v6.octets() },
402-
octets
403-
);
405+
// SAFETY: The `Ipv6Addr` conversion selects the IPv6 variant.
406+
let converted = unsafe { IpAddress::from(core_ipv6_addr).v6.octets() };
407+
assert_eq!(converted, octets);
404408
}
405409
// StdIpAddr -> IpAddress
406410
{
407411
let octets = [8, 8, 2, 6];
408412
let core_ip_addr = core::net::IpAddr::from(octets);
409-
assert_eq!(unsafe { IpAddress::from(core_ip_addr).v4.octets() }, octets);
413+
// SAFETY: This `IpAddr` is built from four octets, so it is IPv4.
414+
let converted = unsafe { IpAddress::from(core_ip_addr).v4.octets() };
415+
assert_eq!(converted, octets);
410416
}
411417
// octets <-> MacAddress
412418
{
@@ -435,15 +441,17 @@ mod tests {
435441
#[test]
436442
fn test_uefi_flow() {
437443
fn efi_retrieve_efi_ip_addr(addr: *mut IpAddress, is_ipv6: bool) {
444+
// SAFETY: The caller passes a valid, writable `IpAddress` pointer.
438445
let addr = unsafe { addr.as_mut().unwrap() };
439-
// SAFETY: Alignment is guaranteed and memory is initialized.
446+
// SAFETY: The selected variant is the one initialized by the caller.
440447
unsafe {
441448
addr.v4.0[0] = 42;
442449
addr.v4.0[1] = 42;
443450
addr.v4.0[2] = 42;
444451
addr.v4.0[3] = 42;
445452
}
446453
if is_ipv6 {
454+
// SAFETY: The IPv6 branch writes the bytes that the caller will read back.
447455
unsafe {
448456
addr.v6.0[14] = 42;
449457
addr.v6.0[15] = 42;
@@ -454,6 +462,7 @@ mod tests {
454462
fn high_level_retrieve_ip(is_ipv6: bool) -> core::net::IpAddr {
455463
let mut efi_ip_addr = IpAddress::ZERO;
456464
efi_retrieve_efi_ip_addr(&mut efi_ip_addr, is_ipv6);
465+
// SAFETY: The helper initialized the variant selected by `is_ipv6`.
457466
unsafe { efi_ip_addr.into_core_addr(is_ipv6) }
458467
}
459468

uefi-raw/src/protocol/hii/image.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,14 @@ pub union ImageOutputDest {
5050

5151
impl fmt::Debug for ImageOutputDest {
5252
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53-
// All union fields are pointers.
54-
f.debug_struct("ImageOutputDest")
55-
.field("bitmap", unsafe { &self.bitmap })
56-
.field("screen", unsafe { &self.screen })
57-
.finish()
53+
// SAFETY: Both union members are raw pointers, so reading either field
54+
// only copies the stored address.
55+
unsafe {
56+
f.debug_struct("ImageOutputDest")
57+
.field("bitmap", &self.bitmap)
58+
.field("screen", &self.screen)
59+
.finish()
60+
}
5861
}
5962
}
6063

uefi-raw/src/protocol/network/pxe.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,18 +302,24 @@ impl Debug for PxeBaseCodePacket {
302302

303303
impl AsRef<[u8; 1472]> for PxeBaseCodePacket {
304304
fn as_ref(&self) -> &[u8; 1472] {
305+
// SAFETY: The packet union is defined with `raw` as the byte view for
306+
// the full storage, and any byte pattern is valid here.
305307
unsafe { &self.raw }
306308
}
307309
}
308310

309311
impl AsRef<PxeBaseCodeDhcpV4Packet> for PxeBaseCodePacket {
310312
fn as_ref(&self) -> &PxeBaseCodeDhcpV4Packet {
313+
// SAFETY: The caller chooses this view; the union stores the packet
314+
// bytes in a layout compatible with the DHCPv4 packet type.
311315
unsafe { &self.dhcpv4 }
312316
}
313317
}
314318

315319
impl AsRef<PxeBaseCodeDhcpV6Packet> for PxeBaseCodePacket {
316320
fn as_ref(&self) -> &PxeBaseCodeDhcpV6Packet {
321+
// SAFETY: The caller chooses this view; the union stores the packet
322+
// bytes in a layout compatible with the DHCPv6 packet type.
317323
unsafe { &self.dhcpv6 }
318324
}
319325
}

uefi/src/allocator.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ fn alloc_pool_aligned(memory_type: MemoryType, size: usize, align: usize) -> *mu
6262
offset = align;
6363
}
6464

65-
// Before returning the aligned allocation, store a pointer to the
66-
// full unaligned allocation in the bytes just before the aligned
67-
// allocation. We know we have at least eight bytes there due to
68-
// adding `align` to the memory allocation size. We also know the
69-
// write is appropriately aligned for a `*mut u8` pointer because
70-
// `align_ptr` is aligned, and alignments are always powers of two
71-
// (as enforced by the `Layout` type).
65+
// SAFETY: `full_alloc_ptr` points to a valid allocation large enough for
66+
// `size + align + size_of::<*mut u8>()`. Adding `offset` keeps
67+
// `aligned_ptr` within that allocation and yields the requested alignment.
68+
// The allocation size includes enough extra space to reserve the bytes
69+
// immediately preceding `aligned_ptr`, where we store `full_alloc_ptr` so
70+
// the original allocation can later be recovered. Because `aligned_ptr` is
71+
// aligned and valid alignments are powers of two as enforced by `Layout`,
72+
// the slot at `aligned_ptr.cast::<*mut u8>().sub(1)` is properly aligned
73+
// for writing a `*mut u8`.
7274
unsafe {
7375
let aligned_ptr = full_alloc_ptr.add(offset);
7476
(aligned_ptr.cast::<*mut u8>()).sub(1).write(full_alloc_ptr);
@@ -100,6 +102,9 @@ const fn layout_allows_page_alloc_shortcut(layout: &Layout) -> bool {
100102
#[derive(Debug)]
101103
pub struct Allocator;
102104

105+
// SAFETY: `alloc` delegates to UEFI's pool allocator, which returns correctly
106+
// aligned, non-aliasing memory. `dealloc` only frees pointers previously returned
107+
// by the matching `alloc` call with the same layout.
103108
unsafe impl GlobalAlloc for Allocator {
104109
/// Allocate memory using the UEFI boot services.
105110
///
@@ -151,19 +156,23 @@ unsafe impl GlobalAlloc for Allocator {
151156
// To spammy, but useful for manual testing.
152157
// log::trace!("Taking PAGE_SIZE shortcut for layout={layout:?}");
153158
let count = layout.size().div_ceil(PAGE_SIZE);
159+
// SAFETY: This pointer was allocated by the matching UEFI allocator.
154160
unsafe { boot::free_pages(ptr, count).unwrap() }
155161
}
156162
(false, 0..=8 /* UEFI default alignment */) => {
157163
// Warning: this will panic after exiting boot services.
164+
// SAFETY: This pointer was allocated by the matching UEFI allocator.
158165
unsafe { boot::free_pool(ptr) }.unwrap();
159166
}
160167
(false, 9..) => {
161168
let ptr = ptr.as_ptr().cast::<*mut u8>();
162-
// Retrieve the pointer to the full allocation that was packed right
163-
// before the aligned allocation in `alloc`.
169+
// SAFETY: Retrieve the in-bounds pointer to the full allocation
170+
// that was packed right before the aligned allocation in
171+
// `alloc()`.
164172
let actual_alloc_ptr = unsafe { ptr.sub(1).read() };
165173
let ptr = NonNull::new(actual_alloc_ptr).unwrap();
166174
// Warning: this will panic after exiting boot services.
175+
// SAFETY: This pointer was allocated by the matching UEFI allocator.
167176
unsafe { boot::free_pool(ptr) }.unwrap();
168177
}
169178
}

0 commit comments

Comments
 (0)