Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2ecc76c

Browse files
committed
uefi-raw: net: covert union to normal type
The union makes some things hard to work with, and we can simply remove it. We get multiple advantages from that: - no more chance to have uninitialized bytes - We can `Debug`-print the type - Some implementations become simpler
1 parent c849bec commit 2ecc76c

File tree

2 files changed

+46
-72
lines changed

2 files changed

+46
-72
lines changed

‎uefi-raw/src/net.rs

Lines changed: 44 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
//! - `[u8; 6]` -> [`MacAddress`]
2929
//! - `[u8; 32]` -> [`MacAddress`]
3030
31-
use core::fmt::{Debug, Formatter};
3231
use core::net::{IpAddr as StdIpAddr, Ipv4Addr as StdIpv4Addr, Ipv6Addr as StdIpv6Addr};
33-
use core::{fmt, mem};
3432

3533
/// An IPv4 internet protocol address.
3634
///
@@ -92,38 +90,27 @@ impl From<Ipv6Address> for StdIpv6Addr {
9290
}
9391
}
9492

95-
/// EFI ABI-compatible union of an IPv4 or IPv6 internet protocol address.
96-
///
97-
/// Corresponds to the `EFI_IP_ADDRESS` type in the UEFI specification. This
98-
/// type is defined in the same way as edk2 for compatibility with C code. Note
99-
/// that this is an **untagged union**, so there's no way to tell which type of
100-
/// address an `IpAddress` value contains without additional context.
93+
/// EFI ABI-compatible union of an IPv4 or IPv6 internet protocol address,
94+
/// corresponding to `EFI_IP_ADDRESS` type in the UEFI specification.
10195
///
10296
/// See the [module documentation] to get an overview over the relation to the
10397
/// types from [`core::net`].
10498
///
99+
/// # UEFI Information
100+
/// Corresponds to the `EFI_IP_ADDRESS` type in the UEFI specification. Instead
101+
/// of using an untagged C union, we use this more rusty type. ABI-wise it is
102+
/// the same but less cumbersome to work with in Rust.
103+
///
105104
/// [module documentation]: self
106-
#[derive(Clone, Copy)]
107-
#[repr(C)]
108-
pub union IpAddress {
109-
/// An IPv4 internet protocol address.
110-
pub v4: Ipv4Address,
111-
112-
/// An IPv6 internet protocol address.
113-
pub v6: Ipv6Address,
114-
115-
/// This member serves to align the whole type to 4 bytes as required by
116-
/// the spec. Note that this is slightly different from `repr(align(4))`,
117-
/// which would prevent placing this type in a packed structure.
118-
align_helper: [u32; 4],
119-
}
105+
#[derive(Debug, Clone, Copy)]
106+
#[repr(C, align(4))]
107+
pub struct IpAddress(pub [u8; 16]);
120108

121109
impl IpAddress {
122110
/// Construct a new zeroed address.
123111
#[must_use]
124112
pub const fn new_zeroed() -> Self {
125-
// SAFETY: All bit patterns are valid.
126-
unsafe { mem::zeroed() }
113+
Self([0; 16])
127114
}
128115

129116
/// Construct a new IPv4 address.
@@ -132,10 +119,9 @@ impl IpAddress {
132119
/// is needed.
133120
#[must_use]
134121
pub const fn new_v4(octets: [u8; 4]) -> Self {
135-
// Initialize all bytes to zero first.
136-
let mut obj = Self::new_zeroed();
137-
obj.v4 = Ipv4Address(octets);
138-
obj
122+
Self([
123+
octets[0], octets[1], octets[2], octets[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124+
])
139125
}
140126

141127
/// Construct a new IPv6 address.
@@ -144,17 +130,14 @@ impl IpAddress {
144130
/// is needed.
145131
#[must_use]
146132
pub const fn new_v6(octets: [u8; 16]) -> Self {
147-
// Initialize all bytes to zero first.
148-
let mut obj = Self::new_zeroed();
149-
obj.v6 = Ipv6Address(octets);
150-
obj
133+
Self(octets)
151134
}
152135

153136
/// Returns the octets of the union. Without additional context, it is not
154137
/// clear whether the octets represent an IPv4 or IPv6 address.
155138
#[must_use]
156139
pub const fn octets(&self) -> [u8; 16] {
157-
unsafe{self.v6.octets()}
140+
self.0
158141
}
159142

160143
/// Returns a raw pointer to the IP address.
@@ -181,11 +164,12 @@ impl IpAddress {
181164
#[must_use]
182165
pub fn to_std_ip_addr(self, is_ipv6: bool) -> StdIpAddr {
183166
if is_ipv6 {
184-
StdIpAddr::V6(StdIpv6Addr::from(unsafe{self.v6.octets()}))
167+
StdIpAddr::V6(StdIpv6Addr::from(self.octets()))
185168
} else {
186169
let has_extra_bytes = self.octets()[4..].iter().any(|&x| x != 0);
187170
assert!(!has_extra_bytes);
188-
StdIpAddr::V4(StdIpv4Addr::from(unsafe { self.v4.octets() }))
171+
let octets: [u8; 4] = self.octets()[..4].try_into().unwrap();
172+
StdIpAddr::V4(StdIpv4Addr::from(octets))
189173
}
190174
}
191175

@@ -212,20 +196,7 @@ impl IpAddress {
212196
/// additional context that the IP is indeed an IPv6 address.
213197
#[must_use]
214198
pub unsafe fn as_ipv6(&self) -> Ipv6Address {
215-
Ipv6Address::from(unsafe { self.v6.octets() })
216-
}
217-
}
218-
219-
impl Debug for IpAddress {
220-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
221-
f.debug_struct("IpAddress")
222-
// SAFETY: All constructors ensure that all bytes are always
223-
// initialized.
224-
.field("v4", &unsafe { self.v4 })
225-
// SAFETY: All constructors ensure that all bytes are always
226-
// initialized.
227-
.field("v6", &unsafe { self.v6 })
228-
.finish()
199+
Ipv6Address::from(self.octets())
229200
}
230201
}
231202

@@ -337,6 +308,18 @@ mod tests {
337308
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
338309
];
339310

311+
/// Ensures ABI-compatibility, as described here:
312+
/// <https://github.com/tianocore/edk2/blob/b1887152024c7eb0cc7de735b0b57febd6099bf9/MdePkg/Include/Uefi/UefiBaseType.h#L100>
313+
#[test]
314+
fn test_abi() {
315+
assert_eq!(size_of::<IpAddress>(), 16);
316+
assert_eq!(align_of::<IpAddress>(), 4);
317+
assert_eq!(size_of::<Ipv4Address>(), 4);
318+
assert_eq!(align_of::<Ipv6Address>(), 1);
319+
assert_eq!(size_of::<Ipv6Address>(), 16);
320+
assert_eq!(align_of::<Ipv6Address>(), 1);
321+
}
322+
340323
/// Test round-trip conversion between `Ipv4Address` and `StdIpv4Addr`.
341324
#[test]
342325
fn test_ip_addr4_conversion() {
@@ -360,11 +343,14 @@ mod tests {
360343
fn test_ip_addr_conversion() {
361344
let core_addr = StdIpAddr::V4(StdIpv4Addr::from(TEST_IPV4));
362345
let uefi_addr = IpAddress::from(core_addr);
363-
assert_eq!(unsafe { uefi_addr.v4.0 }, TEST_IPV4);
346+
assert_eq!(
347+
unsafe { uefi_addr.try_as_ipv4().unwrap() }.octets(),
348+
TEST_IPV4
349+
);
364350

365351
let core_addr = StdIpAddr::V6(StdIpv6Addr::from(TEST_IPV6));
366352
let uefi_addr = IpAddress::from(core_addr);
367-
assert_eq!(unsafe { uefi_addr.v6.0}, TEST_IPV6);
353+
assert_eq!(unsafe { uefi_addr.as_ipv6()}.octets(), TEST_IPV6);
368354
}
369355

370356
/// Tests the From-impls as described in the module description.
@@ -414,30 +400,18 @@ mod tests {
414400
}
415401
}
416402

417-
/// Tests that all bytes are initialized and that the Debug print doesn't
418-
/// produce errors, when Miri executes this.
419-
#[test]
420-
fn test_ip_address_debug_memory_safe() {
421-
let uefi_addr = IpAddress::new_v6(TEST_IPV6);
422-
std::eprintln!("{uefi_addr:#?}");
423-
}
424-
425403
/// Tests the expected flow of types in a higher-level UEFI API.
426404
#[test]
427405
fn test_uefi_flow() {
428406
fn efi_retrieve_efi_ip_addr(addr: &mut IpAddress, is_ipv6: bool) {
429-
// SAFETY: Alignment is guaranteed and memory is initialized.
430-
unsafe {
431-
addr.v4.0[0] = 42;
432-
addr.v4.0[1] = 42;
433-
addr.v4.0[2] = 42;
434-
addr.v4.0[3] = 42;
435-
}
407+
addr.0[0] = 42;
408+
addr.0[1] = 42;
409+
addr.0[2] = 42;
410+
addr.0[3] = 42;
411+
436412
if is_ipv6 {
437-
unsafe {
438-
addr.v6.0[14] = 42;
439-
addr.v6.0[15] = 42;
440-
}
413+
addr.0[14] = 42;
414+
addr.0[15] = 42;
441415
}
442416
}
443417

‎uefi/src/proto/network/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ impl IpAddress {
4444
#[must_use]
4545
const unsafe fn from_raw(ip_addr: uefi_raw::IpAddress, is_ipv6: bool) -> Self {
4646
if is_ipv6 {
47-
Self::new_v6(unsafe{ip_addr.v6.0})
47+
Self::new_v6(ip_addr.0)
4848
} else {
49-
Self::new_v4(unsafe{ ip_addr.v4.0})
49+
Self::new_v4([ip_addr.0[0], ip_addr.0[1], ip_addr.0[2], ip_addr.0[3]])
5050
}
5151
}
5252

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /