Skip to content
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

Add try_alloc and try_alloc_pinned to kernel module. #45

Merged
merged 1 commit into from
Dec 8, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions rust/kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ compile_error!("Missing kernel configuration for conditional compilation");

extern crate alloc;

use alloc::boxed::Box;
use core::alloc::Layout;
use core::mem::MaybeUninit;
use core::panic::PanicInfo;
use core::pin::Pin;
use core::ptr::NonNull;

mod allocator;
pub mod bindings;
Expand Down Expand Up @@ -56,3 +61,33 @@ fn panic(_info: &PanicInfo) -> ! {

#[global_allocator]
static ALLOCATOR: allocator::KernelAllocator = allocator::KernelAllocator;

/// Attempts to allocate memory for `value` using the global allocator. On success, `value` is
/// moved into it and returned to the caller wrapped in a `Box`.
pub fn try_alloc<T>(value: T) -> KernelResult<Box<T>> {
let layout = Layout::new::<MaybeUninit<T>>();
let ptr: NonNull<MaybeUninit<T>> = if layout.size() == 0 {
NonNull::dangling()
// SAFETY: We checked that the layout size is nonzero.
} else if let Some(nn) = NonNull::new(unsafe { alloc::alloc::alloc(layout) }) {
nn.cast()
} else {
return Err(Error::ENOMEM);
};

unsafe {
// SAFETY: `ptr` was just allocated and isn't used afterwards.
let mut b = Box::from_raw(ptr.as_ptr());
// SAFETY: The pointer is valid for write and is properly aligned. The dangling pointer
// case is only when the size of the value is zero; writing zero bytes to it is allowed.
b.as_mut_ptr().write(value);
// SAFETY: The value was initialised in the call above.
Ok(Box::from_raw(Box::into_raw(b) as *mut T))
}
Copy link
Member

Choose a reason for hiding this comment

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

Based on how Box works, I think we want something a little smarter. Looking at:

We want something like:

        let layout = Layout::new::<mem::MaybeUninit<T>>();
        let ptr = alloc::alloc::alloc(layout);
        // Handle nul ptr here
        let mut b = unsafe { Box::from_raw(ptr.as_ptr()) };
        b.as_mut_ptr().write(value);
        b.assume_init()

Copy link
Author

Choose a reason for hiding this comment

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

For my own benefit: do you see any UB in the code above?

I've updated the code as you suggested. In process of adding SAFETY comments, I noticed that we cannot call alloc with a zero-sized layout, so I added some code to take care of that.

I also don't call assume_init() because it requires some nightly feature. I just do the into_raw/from_raw dance.

PTAL.

}

/// Attempts to allocate memory for `value` using the global allocator. On success, `value` is
/// moved into it and returned to the caller wrapped in a pinned `Box`.
pub fn try_alloc_pinned<T>(value: T) -> KernelResult<Pin<Box<T>>> {
Ok(Pin::from(try_alloc(value)?))
}