Today I did a little pointer exercise using Rust.
This is what we are going to do:
1. Allocate a new instance of `Point` struct on the heap
use std::ptr; struct Point { x: u8, y: u8, z: u8, } fn main() { let mut point = Box::new(Point { x: 0, y: 0, z: 0 }); }
2. Change values of Point instance inside `Box<T>`
point.x = u8::max_value(); // 0 point.y = u8::min_value(); // 255 point.z = u8::max_value(); // 0
3. Inspect the memory addr of the `Box<T>` and the values of primitive types by using existing scope reference of the current stack (safe)
// get raw memory address of `Box<Point>`: // &point: get reference to `point` // as *const Box<Point>: cast reference into raw pointer of type T // as usize: cast raw pointer of type T into usize let mem_addr_of_box = &point as *const Box<Point> as usize; // get raw memory address of `Point`: // &*point: get reference to `Point` by dereferenceing instance of `Box<Point>` first // as *const Point: cast reference into raw pointer of type T // as usize: cast raw pointer of type T into usize let mem_addr_of_point_inside_box = &*point as *const Point as usize; let x = point.x; let y = point.y; let z = point.z;
4. Inspect the memory addr of the `Box<T>` and the values of primitive types by reading from raw memory by address as u32 (unsafe)
// get raw memory address of `Box<Point>` from the current scope. let addr = &point as *const Box<Point>; // cast raw pointer of type T into usize let mem_addr_of_box = addr as usize; // perform unsafe raw memory read of `Box<Point>` resulting in raw pointer to `Point`. // as *const usize: casing into usize because addr is a memory address let mem_addr_of_point = unsafe { ptr::read(addr as *const usize) }; // perform unsafe raw memory read of `Point` as type `u32`: // read(...) as *const u32: read `Point` as u32 to inspect binary value & layout // u32 is sufficient as 3x u8 fit inside a u32 let point_value = unsafe { ptr::read_unaligned(ptr::read(addr as *const usize) as *const u32) };
5. Read point as `Point` from memory by raw pointer address into stack variable (unsafe) (values are copied)
// perform unsafe raw memory read of `Box<Point>` -> `Point` as type `Point`. let point = unsafe { ptr::read(ptr::read(addr as *const usize) as *const Point) }; // get raw memory address of `Point`: // as *const Point: cast reference into raw pointer of type T // as usize: cast raw pointer of type T into usize let mem_addr_of_point = &point as *const Point as usize; let x = point.x; let y = point.y; let z = point.z;
And here is an example of how that could look like in action Code Snippet Rust Playground via godbolt.org