How does `integer-pointer` work in the embedded platform?

std::ptr - Rust says:

In other words, pointer-integer-pointer roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable).

I am curious if an embedded platform says we should write something to the address 0x0010 to make some work, how it work with rust on that platform? For example:

fn main() {
    let ptr = 0x0010 as *mut u8;
    unsafe {
        *ptr = 1; // #1 make the beep sound
    };
}

The current Rust document says that #1 can cause UB. MIRI says:

error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)

However, assuming this is a practical code in that platform, how does Rust work on that platform?

Update

A first attempt in Rust - The Embedded Rust Book has a similar scenario, which uses the crate volatile-register

#[repr(C)]
struct SysTick {
    pub csr: RW<u32>,
    pub rvr: RW<u32>,
    pub cvr: RW<u32>,
    pub calib: RO<u32>,
}

fn get_systick() -> &'static mut SysTick {
    unsafe { &mut *(0xE000_E010 as *mut SysTick) }
}

fn get_time() -> u32 {
    let systick = get_systick();
    systick.cvr.read()
}

fn main() {
    get_time();
}

The Miri says this is UB

error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 16 bytes of memory, but got 0xe000e010[noalloc] which is a dangling pointer (it has no provenance)

Here is the discussion on this topic for the strict provenance experiment: [strict provenance] Provide a way to "create allocations at a fixed address" · Issue #98593 · rust-lang/rust · GitHub

The code is fine, but only on platforms where 0x10 is an mmio address. Miri is not such a platform, so it fails in miri but works on real hardware.

3 Likes

The current document of std::ptr says:

Most code needs no changes to conform to strict provenance, as the only really concerning operation that wasn’t obviously already Undefined Behaviour is casts from usize to a pointer.

In other words, pointer-integer-pointer roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable).

Under Strict Provenance it is Undefined Behaviour to:

Access memory through a pointer that does not have provenance over that memory.

This is saying that dereference the result of converting integer to pointer is UB

"under strict provenance"

Strict provenance is not the real ruleset of Rust. Rather, strict provenance is a set of rules that:

  1. Is relatively easy to teach.
  2. Is not overly restrictive, i.e. most programs can follow strict provenance without issues.
  3. Can be emulated perfectly by interpreters such as miri.
  4. Is more strict than the real rules.

Anything that is ok under strict provenance is also ok under the real ruleset, but the reverse is not true. There are things that are rejected by strict provenance, but ok under the real rules. Mmio access by casting an integer to pointer is one such thing.

6 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.