Lifetime of iterator, borrowed value does not live long enough

In my bootloader implementation, I encountered a problem. Could anybody help me?

#[entry]
fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
    ...
    let bs = system_table.boot_services();
    ...
    let mmap_storage = Box::leak(vec![0; bs.memory_map_size().map_size * 2].into_boxed_slice());
    ...
    let (_rs, mut mmap_iter) = system_table.exit_boot_services(handle, mmap_storage).expect("Failed to exit boot services");
    ...
    let boot_info = BootInfo{ memory_map: &mut mmap_iter, physical_memory_offset: config.physical_memory_offset };
 //                                       ^^^^^^^^^^^^^^ borrowed value does not live long enough
    unsafe {
        jump_to_entry(stacktop, &boot_info);
    }
} // `mmap_iter` dropped here while still borrowed

// not working
#[repr(C)]
pub struct BootInfo<'a> {
    pub memory_map: &'a mut dyn ExactSizeIterator<Item=&'a MemoryDescriptor>,
    pub physical_memory_offset: u64,
}

// not working
#[repr(C)]
pub struct BootInfo<'a: 'b, 'b> {
    pub memory_map: &'a mut dyn ExactSizeIterator<Item=&'b MemoryDescriptor>,
    /// The offset where the physical memory is mapped at in the virtual address space.
    pub physical_memory_offset: u64,
}

// working
#[repr(C)]
pub struct BootInfo<'a, 'b> {
    pub memory_map: &'a mut dyn ExactSizeIterator<Item=&'b MemoryDescriptor>,
    /// The offset where the physical memory is mapped at in the virtual address space.
    pub physical_memory_offset: u64,
}

// working
#[repr(C)]
pub struct BootInfo<'a, 'b: 'a> {
    pub memory_map: &'a mut dyn ExactSizeIterator<Item=&'b MemoryDescriptor>,
    /// The offset where the physical memory is mapped at in the virtual address space.
    pub physical_memory_offset: u64,
}

And here are some relevant sinatures.

// https://github.com/rust-osdev/uefi-rs/blob/bfa88e18e3aea339711b8de9a5148add13f98776/src/table/system.rs#L174
pub fn exit_boot_services(
    self,
    image: Handle,
    mmap_buf: &mut [u8],
) -> Result<(
    SystemTable<Runtime>,
    impl ExactSizeIterator<Item = &MemoryDescriptor> + Clone,
)> {
    unsafe {
        let boot_services = self.boot_services();

        loop {
            let mmap_buf = &mut *(mmap_buf as *mut [u8]);
            let mmap_comp = boot_services.memory_map(mmap_buf)?;  // -
            let (mmap_key, mmap_iter) = mmap_comp;                // |
            ...                                                   // |
        }                                                         // |
    }                                                             // |
}                                                                 // |
                                                                  // |
// https://github.com/rust-osdev/uefi-rs/blob/bfa88e18e3aea339711b8de9a5148add13f98776/src/table/boot.rs#L327
pub fn memory_map<'buf>(                 // -------------------------|
    &self,
    buffer: &'buf mut [u8],
) -> Result<(
    MemoryMapKey,
    impl ExactSizeIterator<Item = &'buf MemoryDescriptor> + Clone,
)> {
    ...
    unsafe {
        (self.get_memory_map)(
            &mut map_size,
            map_buffer,
            &mut map_key,
            &mut entry_size,
            &mut entry_version,
        )
    }
    .into_with_val(move || {
        let len = map_size / entry_size;
        let iter = MemoryMapIter {
            buffer,
            entry_size,
            index: 0,
            len,
        };
        (map_key, iter)
    })
}

The problem is that the first and the second definition of your BootInfo struct are overly restricting. They require the reference to mmap_iter to live as long as the references it yields, however those references have a 'static lifetime (or, more generally, a bigger lifetime), and so the restriction can't be satisfied. Furthermore, the lifetime of the items can't be restricted due to being behind a dyn Trait/impl Trait, which hides from the compiler whether that lifetime can be shrinked or not.

The third and fourth definitions of BootInfo don't require the reference to mmap_iter to outlive the references yielded. If anything, the fourth one requires the opposite, that is the references yielded to outlive the reference to mmap_iter.

2 Likes