Master the fundamental concepts of rust for systems programming through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksSafe Rust proves memory and thread safety at compile time. unsafe is an explicit escape hatch for operations the compiler cannot verify: dereferencing raw pointers, calling FFI, touching static mut, or implementing unsafe traits like Send manually.
rustLoading…
unsafe block should be the smallest possible scope with a comment stating the invariant you upholdFFI to C, intrusive data structures, device MMIO, and hot paths that need from_utf8_unchecked-style promises. The standard library uses unsafe internally so your safe APIs stay fast.
For this exercise, you will manipulate raw pointers and call an unsafe fn behind a safe wrapper. This task asks you to document the safety contract your wrapper enforces, because "just slap unsafe on it" is how Rust projects recreate C bugs with extra steps.
Keep the relevant man page, ABI doc, or Rust reference chapter open while you work. When your output disagrees with the reference implementation on the same machine, the mismatch is usually an alignment rule, an off-by-one terminator, or a register slot you misread in GDB.
Write a tiny Miri: a byte buffer accessed through raw pointers, which checks every access for undefined behaviour before performing it. In Rust, unsafe does not turn off the rules. It makes you responsible for them: non-null, in bounds, not freed, correctly aligned, and non-overlapping for copy_nonoverlapping. Your program enforces exactly those rules.
One command per line. Numbers are decimal, or hex with a 0x prefix. TYPE is u8, u16, u32 or u64 (size = alignment = 1, 2, 4, 8). All multi-byte values are little-endian.
cLoading…
UB: null pointer dereference. Buffer freed: UB: use after free.[OFF, OFF+SIZE) must fit: UB: out-of-bounds access: [A, B) in a N-byte buffer (for a copy, check the source range first, then the destination).OFF % SIZE == 0: UB: misaligned read of u32 at offset 1 (needs alignment 4) (or write).copy_nonoverlapping with overlapping non-empty ranges: UB: copy_nonoverlapping with overlapping ranges [A, B) and [C, D).free without a buffer prints UB: free of a null pointer, and a second free prints UB: double free. When UB is detected, the operation does not happen.
alloc: allocated N bytes (align 8). free: freed. write: nothing.read: u32 at 4 = 0x11223344 (hex, zero-padded to 2 digits per byte).copy: copied N bytes (byte when N is 1). dump: the bytes as two-digit hex separated by spaces.error: bad command: LINE (unknown command or wrong argument count), error: unknown type T, error: bad number, error: VALUE out of range for T, error: alloc size must be 1..64.Input:
cLoading…
Output:
cLoading…
base.add(off), ptr::read/write, ptr::copy), and put each unsafe block behind the checks that make it sound.Vec<u64> viewed as bytes), so the aligned forms really are aligned.Hidden tests cover access before alloc, use after free and double free, boundary accesses at the last byte, unaligned u16/u64 access, overlapping ptr::copy in both directions, and malformed commands.