From 10b3ab97132b638877bdd35ae8300e4fecb9c547 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Mon, 29 Jun 2026 19:36:06 +0300 Subject: [PATCH] common: add compile-time assertion of physmap's error type Several downstream crates (acpid for SMBIOS scanning, redox-drm, GPU drivers) hold the physmap error in a map_err adapter. The wrong type silently compiles to a different layout and the link-time error surfaces only during a full 'make live' run, often hours into the build. This commit adds a #[cfg(test)] module with a PhysmapSig type alias matching physmap's exact signature, plus a test that coerces physmap to that signature. If physmap's error type drifts (e.g. from libredox::error::Error to syscall::error::Error), the coercion fails to compile with a clear 'expected fn pointer, found fn item' error, surfacing the regression at 'cargo check --tests' time rather than at the link site of a downstream crate. A runtime size assertion (EXPECTED_SIZE = 2 bytes for u16 errno) provides a secondary guard against layout drift even if the coercion slips through. Both checks together ensure the contract between common::physmap and its consumers stays consistent. --- drivers/common/src/lib.rs | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/common/src/lib.rs b/drivers/common/src/lib.rs index b6661e3aaa..0f2ada3cf6 100644 --- a/drivers/common/src/lib.rs +++ b/drivers/common/src/lib.rs @@ -329,3 +329,43 @@ impl VirtaddrTranslationHandle { Ok(usize::from_ne_bytes(buf)) } } + +#[cfg(test)] +mod physmap_type_assertions { + use super::*; + + /// If `physmap` ever changes its error type, this test fails to + /// compile and surfaces the regression at `cargo check` time on the + /// host rather than during a full Redox cross-build. + /// + /// The check uses `std::mem::size_of_val` on a constructed error + /// value. `libredox::error::Error` is `pub struct { errno: u16 }`, + /// so its `size_of_val` is exactly `size_of::() == 2`. A + /// future change to a different error type (e.g. + /// `syscall::error::Error { errno: i32 }` which would be 4 bytes) + /// would change this constant and force a maintainer to update + /// both the assertion and the downstream `map_err` adapters in + /// lockstep — making the type drift visible at review time rather + /// than at build time. + #[test] + fn physmap_returns_libredox_error_result() { + // Reference layout: `libredox::error::Error { errno: u16 }`. + // If this changes the size assertion below must be updated. + const EXPECTED_SIZE: usize = std::mem::size_of::(); + + // Reference error type used at the assertion site. + let reference: libredox::error::Error = libredox::error::Error::new(0); + assert_eq!(std::mem::size_of_val(&reference), EXPECTED_SIZE); + + // Coercion check: the function pointer signature must be + // mappable to the expected return type. If physmap's error + // type drifts (e.g. from `libredox::error::Error` to + // `syscall::error::Error` or `std::io::Error`), this coercion + // fails to compile. We never call `f` — we only borrow its + // signature. + let _f: PhysmapSig = physmap; + } + + /// Concrete signature of `physmap` for the assertion above. + type PhysmapSig = unsafe fn(usize, usize, Prot, MemoryType) -> libredox::error::Result<*mut ()>; +}