Skip to content

Add API test and improve memory safety in MMIO constructors#54

Open
phip1611 wants to merge 2 commits intorust-osdev:mainfrom
phip1611:safety
Open

Add API test and improve memory safety in MMIO constructors#54
phip1611 wants to merge 2 commits intorust-osdev:mainfrom
phip1611:safety

Conversation

@phip1611
Copy link
Member

@phip1611 phip1611 commented Mar 24, 2026

This PR makes two changes to the uart_16550 crate.

First, a compile-only API test is added to guard against accidental breakage of public exports. Without it, removing Backend from the public API would go undetected as long as direct constructors still compiled.

Second, new_mmio() on both Uart16550 and Uart16550Tty now takes NonNull<u8> instead of *mut u8. The previous 0x1000 as *mut u8 cast produced a pointer with unspecified provenance, which is unsound under Rust's abstract machine even if it works in practice. The correct approach since Rust 1.84 is ptr::with_exposed_provenance_mut(), which makes provenance explicit for addresses pointing outside the Rust abstract machine — exactly the MMIO use case.

This is a breaking change: callers must update their pointer construction accordingly. As a side effect, null-pointer validation moves from runtime to the type system, so InvalidAddressError::Null has been removed.

Closes #52.

Having such tests is useful. Without it, it could happen that `Backend`
isn't exported anymore - which would still enable to create instances
via the constructors but one can't create bindings anymore. This test
therefore protects against that. The test succeeds if the test compiles.
@phip1611 phip1611 self-assigned this Mar 24, 2026
Casting an integer address to a raw pointer with `0x1000 as *mut u8`
produces a pointer with unspecified provenance in Rust's abstract
machine, which is technically unsound even if it works in practice.

The correct, stabilized API for constructing pointers to memory that
lives outside the Rust abstract machine (such as MMIO regions) is
ptr::with_exposed_provenance_mut(), introduced in Rust 1.84. Combined
with NonNull, this makes the provenance model explicit and well-defined.

    let mmio_address = ptr::with_exposed_provenance_mut::<u8>(0x1000);
    let mmio_address = NonNull::new(mmio_address).unwrap();

This is a breaking change: callers must now pass NonNull<u8> instead of
*mut u8. As a consequence, null-pointer validation is now enforced by
the type system rather than at runtime, so InvalidAddressError::Null has
been removed.
@phip1611
Copy link
Member Author

After that, I'd ship v0.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integer-to-pointer casts + use NonNull for MMIO constructor

1 participant