Skip to content

Memory map change #915

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2023
Merged

Conversation

julic20s
Copy link
Contributor

@julic20s julic20s commented Aug 10, 2023

Remove the reference type in iterator which results in incorrect lifetime for return value of MemoryMap::entries()
Change prototype of exit_boot_services()
For #914

Checklist

  • Sensible git history (for example, squash "typo" or "fix" commits). See the Rewriting History guide for help.
  • Update the changelog (if necessary)

Sorry, something went wrong.

@julic20s julic20s force-pushed the memory-map-change branch 3 times, most recently from abea9ce to da896c9 Compare August 12, 2023 07:32
@nicholasbishop
Copy link
Member

Thanks for the PR!

The change to add a MemoryType parameter to exit_boot_services seems reasonable, I'm happy to accept that.

I'm a little less sure about the lifetime fix. While I think what you have probably works fine for exit_boot_services, where the lifetime is static, it's possible to get the memory map prior to that via BootServices::memory_map, and I'm not 100% sure your code is correct for that situation. The tricky thing here is that MemoryMap contains a mut reference, which places stricter bounds on the lifetime of &self methods. See this example on the playground. I'm not sure that the unsafe isn't just laundering lifetimes in a UB way.

It seems like there's a conflict here between having the mutable sort method on MemoryMap, and the desire to have MemoryMapIter have a lifetime matching the MemoryMap 'buf lifetime, and if possible I'd like to solve it without unsafe. A couple ideas:

  1. We could rename MemoryMap to MemoryMapMut, and a second MemoryMap type that contains non-mut reference to the data. Then add a conversion method to MemoryMapMut that consumes self and returns a MemoryMap.
  2. We could change MemoryMap::entries to consume self, which would allow MemoryMapIter<'buf> to be returned. The downside is that you wouldn't be able to call MemoryMap::key after that, and you'd only get one iteration unless we modified MemoryMapIter to have a reset method or something like that.

There may be other options, open to ideas here :)

@julic20s
Copy link
Contributor Author

julic20s commented Aug 13, 2023

@nicholasbishop

I'm a little less sure about the lifetime fix. While I think what you have probably works fine for exit_boot_services, where the lifetime is static, it's possible to get the memory map prior to that via BootServices::memory_map, and I'm not 100% sure your code is correct for that situation.

The MemoryMapIter get the buffer's location from MemoryMap and keep it's lifetime. So I think that it's equivalent between my code and the current MemoryMapIter implementation in ther master branch. (Use *const u8 + PhantomData<'buf> instead of &'buf mut [u8]) The point is that the 'buf tracking the buffer's lifetime but not MemoryMap's.

I'm not sure that the unsafe isn't just laundering lifetimes in a UB way.

But I'm not sure if there are some of unsafe and UB that you mentioned. Could you tell me about it? In MemoryMap::entries() and MemoryMapIter, only MemoryMapIter::next() use a unsafe block.

@nicholasbishop
Copy link
Member

Here's a concrete example showing UB:

fn test_mem_map(bt: &BootServices) {
    let sizes = bt.memory_map_size();
    let mut buffer = vec![0; sizes.map_size * sizes.entry_size];
    let mut memory_map = bt.memory_map(&mut buffer).unwrap();

    let mut entries = memory_map.entries();
    info!("first entry: {:?}", entries.next());
    // UB! The data being iterated over is modified while we have a supposedly
    // immutable reference to the data.
    memory_map.sort();
    info!("next entry: {:?}", entries.next());
}

In the main branch this won't compile; the call to memory_map.sort() fails because memory_map is already borrowed as immutable. But it does compile on top of this PR, because the use of a raw pointer prevents this lifetime analysis.

@julic20s julic20s force-pushed the memory-map-change branch 3 times, most recently from dd439a3 to fe0a43c Compare August 17, 2023 06:37
@julic20s julic20s marked this pull request as draft August 20, 2023 04:55
@julic20s julic20s marked this pull request as ready for review August 24, 2023 06:25
@julic20s julic20s force-pushed the memory-map-change branch 2 times, most recently from 96fc71d to 9c9e206 Compare August 24, 2023 06:42
Copy link
Member

@nicholasbishop nicholasbishop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm for the addition of the memory type param, thanks!

@nicholasbishop nicholasbishop added this pull request to the merge queue Aug 28, 2023
Merged via the queue into rust-osdev:main with commit d4c2ea6 Aug 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants