0

Conceptually, we're looking to create multiple memory pools, with each pool individually acting as a stack. Within each stack, we allocate objects of varying sizes and free them up in a stack-like fashion. We also want to be able to allocate memory from the stacks in an ad-hoc fashion, and not iteratively visit each stack in order.

We found the Scratchpad crate which does the stack allocation and freeing.

The problem is that an allocation is statically bound to the lifetime of the Marker and the Marker is statically bound to the lifetime of the Scratchpad. While we don’t want allocations to outlive the corresponding allocated memory, the lifetime check makes it difficult (or perhaps impossible?) to put the scratchpad, markers and allocations in one object.

In the simple example shown, this can be worked around by including the Scratchpad by reference, but I’m not sure that this can be generalized to the use case that we want where multiple markers and allocations are stored together.

Here is the sample code which does not compile:

extern crate scratchpad;
use scratchpad::{MarkerFront, Scratchpad};

#[derive(Debug)]
struct Stuff<'sp: 'a, 'a> {
    scratchpad: Scratchpad<&'sp mut [u8], &'sp mut [usize]>,
    marker: Option<MarkerFront<'a, &'sp mut [u8], &'sp mut [usize]>>,
}

fn main() {
    let pool0: &mut [u8] = &mut [0; 1024];
    let pool1: &mut [usize] = &mut [0; 64];

    let sp = Scratchpad::new(pool0, pool1);
    let mut stuff = Stuff {
        scratchpad: sp,
        marker: None,
    };
    stuff.marker = Some(stuff.scratchpad.mark_front().unwrap());
    println!("{:?}", stuff);
    stuff.marker = None;
    println!("{:?}", stuff);
} 
error[E0597]: `stuff.scratchpad` does not live long enough
  --> src/main.rs:19:25
   |
19 |     stuff.marker = Some(stuff.scratchpad.mark_front().unwrap());
   |                         ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
23 | }
   | - `stuff.scratchpad` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

Sample code which does compile:

extern crate scratchpad;
use scratchpad::{MarkerFront, Scratchpad};

#[derive(Debug)]
struct Stuff<'sp: 'a, 'a> {
    // This is now a reference
    scratchpad: &'sp Scratchpad<&'sp mut [u8], &'sp mut [usize]>,
    marker: Option<MarkerFront<'a, &'sp mut [u8], &'sp mut [usize]>>,
}

fn main() {
    let pool0: &mut [u8] = &mut [0; 1024];
    let pool1: &mut [usize] = &mut [0; 64];

    let sp = Scratchpad::new(pool0, pool1);
    let mut stuff = Stuff {
        scratchpad: &sp,
        marker: None,
    };
    stuff.marker = Some(stuff.scratchpad.mark_front().unwrap());
    println!("{:?}", stuff);
    stuff.marker = None;
    println!("{:?}", stuff);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • *put the scratchpad, markers and allocations in one object* — Have you already read [Why can't I store a value and a reference to that value in the same struct](https://stackoverflow.com/q/32300132/155423)? It really sounds like you have the exact problem described by it. – Shepmaster Jun 14 '18 at 17:27
  • Especially since what you are attempting to to is **unsafe** and would lead to memory safety bugs. You are attempting to allocate inside of a stack-allocated array. When you move that into the `Scratchpad` and every time you move the `Scratchpad` you'd be moving the array, invalidating any references into it. Rust has prevented you from shooting yourself in the foot. – Shepmaster Jun 14 '18 at 17:31

0 Answers0