CompileNix's Blog - Rust Pointer Exercise

Start Page | RSS Feed | Find Stuff

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
  2. Change values of Point instance inside `Box<T>`
  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)
  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)
  5. Read point as `Point` from memory by raw pointer address into stack variable (unsafe) (values are copied)

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