-
Notifications
You must be signed in to change notification settings - Fork 158
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 unsafe_protocol
macro and drop use of the unstable negative_impls
feature
#607
Add unsafe_protocol
macro and drop use of the unstable negative_impls
feature
#607
Conversation
@@ -80,8 +80,7 @@ fn test_watchdog(bt: &BootServices) { | |||
} | |||
|
|||
/// Dummy protocol for tests | |||
#[unsafe_guid("1a972918-3f69-4b5d-8cb4-cece2309c7f5")] | |||
#[derive(Protocol)] | |||
#[unsafe_protocol("1a972918-3f69-4b5d-8cb4-cece2309c7f5")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general question: why does it need to be called unsafe
, tho? Why can't the attribute be called uefi_protocol("...")
? I do not see a benefit of the prefix unsafe here and it only adds confusion.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's called unsafe_protocol
my question would be what makes it unsafe / how do I use it safely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's prefixed with unsafe_
because passing in the wrong GUID can easily lead to unsoundness.
Here's a quick example of how bad things can happen:
The definition of EFI_DISK_IO_PROTOCOL
from the spec is:
#define EFI_DISK_IO_PROTOCOL_GUID \
{0xCE345171,0xBA0B,0x11d2,\
{0x8e,0x4F,0x00,0xa0,0xc9,0x69,0x72,0x3b}}
typedef struct _EFI_DISK_IO_PROTOCOL {
UINT64 Revision;
EFI_DISK_READ ReadDisk;
EFI_DISK_WRITE WriteDisk;
} EFI_DISK_IO_PROTOCOL;
Now consider this Rust code:
#[repr(C)]
// Bad!
#[unsafe_protocol("ce345171-ba0b-11d2-8e4f-00a0c969723b")]
pub struct MyCoolType {
do_it: extern "efiapi" fn(),
}
let handle = bt.get_handle_for_protocol::<MyCoolType>().unwrap();
let c = bt.open_protocol_exclusive::<MyCoolType>(handle).unwrap();
(c.do_it)();
I've defined a protocol called MyCoolType
with the same GUID as EFI_DISK_IO_PROTOCOL
. When I call get_handle_for_protocol
and open_protocol_exclusive
, UEFI will think it's looking for a disk handle and opening the disk IO protocol. So those calls will succeed, and although c
will be a ScopedProtocol<MyCoolType>
, it will contain completely invalid data.
The docstring has a # Safety
section: https://github.com/rust-osdev/uefi-rs/pull/607/files#diff-ff7f936d7319fc633630baca626659855f359b7185c91237bc9d68bd798256aeR33. There's not much too it; you have to make sure the type and GUID are correct and match up. Definitely open to improving or expanding that paragraph if you have suggestions though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, thanks for the clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
@@ -142,7 +142,6 @@ pub enum FileInfoCreationError { | |||
/// attribute. Other changes must be carried out in a separate transaction. | |||
#[derive(Debug, Eq, PartialEq)] | |||
#[repr(C)] | |||
#[unsafe_guid("09576e92-6d3f-11d2-8e39-00a0c969723b")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch! thanks for fixing this
Awesome work @nicholasbishop, thanks! |
Switch the tests from using `unsafe_guid!` to `guid!`. Both use the same internal code, so we're testing more or less the same thing, but `guid!` is a little more direct. Also, as we previously did with the entry macro, split the GUID tests into multiple files to make it easier to visually inspect the error output. The "good" test case has been removed since that's already covered in plenty of places elsewhere.
The `unsafe_guid` macro is almost always used for creating protocols. There are three other uses though, for identifying file info types. Replace these with explicit impls of the `Identify` trait. Now that we have a `guid!` macro, this doesn't reduce the clarity of the code at all.
This attribute macro combines the functionality of the `unsafe_guid` attribute macro and the `Protocol` derive macro. It impls the `Protocol` and `Identify` traits, and it also marks the type as `!Send` and `!Sync`. This provides a slightly nicer API for protocols (`unsafe_protocol` is a clearer name than `unsafe_guid`, and only one macro is needed instead of two), but more importantly it does the `!Send` and `!Sync` part via a hidden `PhantomData` field rather than relying on the unstable `negative_impls` feature.
Switch all uses of `unsafe_guid!` + `derive(Protocol)` to using `unsafe_protocol!`. Also update the docstrings for the `Identify` and `Protocol` traits.
These are no longer used anywhere.
This is no longer used anywhere.
d51b573
to
19e29dc
Compare
Our protocols are all marked
!Send
and!Sync
using the unstablenegative_impls
feature. There's another way to mark things!Send
and!Sync
though: add a field that itself is!Send
and!Sync
, for example a raw pointer. We don't want to actually change the struct layout of course, but we can use thePhantomData
type for this.The new
unsafe_protocol
macro implements this idea; it's an attribute macro that combines the functionality of theunsafe_guid
attribute macro and theProtocol
derive macro, as well as adding a hiddencore::marker::PhantomData<*const u8>
field for!Send
and!Sync
.The real purpose of this change is to remove use of the unstable
negative_impls
feature towards our goal of building on the stable channel. But it also ends up with a slightly nicer API as well.Short log:
unsafe_guid
unsafe_protocol
macrounsafe_protocol!
for all protocol implsnegative_impls
featureTracking issue for unstable features: #452
Checklist