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

Transmuting enums is UB #92

Open
Pzixel opened this issue Mar 15, 2019 · 5 comments
Open

Transmuting enums is UB #92

Pzixel opened this issue Mar 15, 2019 · 5 comments

Comments

@Pzixel
Copy link

Pzixel commented Mar 15, 2019

Looking at code I found that you are performing UB conversion from primitive to enum

anne-key/src/protocol.rs

Lines 10 to 35 in ac02810

#[repr(u8)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum MsgType {
Reserved = 0,
Error = 1,
System = 2,
Ack = 3,
Reboot = 4,
Macro = 5,
Ble = 6,
Keyboard = 7,
Keyup = 8,
Led = 9,
FwInfo = 10,
FwUp = 11,
CustomLed = 12,
CustomKey = 13,
}
impl From<u8> for MsgType {
#[inline]
fn from(b: u8) -> Self {
unsafe { transmute(b) }
}
}

#[repr(u8)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum MsgType {
    Reserved = 0,
    Error = 1,
    System = 2,
    Ack = 3,
    Reboot = 4,
    Macro = 5,
    Ble = 6,
    Keyboard = 7,
    Keyup = 8,
    Led = 9,
    FwInfo = 10,
    FwUp = 11,
    CustomLed = 12,
    CustomKey = 13,
}

impl From<u8> for MsgType {
    #[inline]
    fn from(b: u8) -> Self {
        unsafe { transmute(b) }
    }
}

You may argue "Hey, but there is an attribute", but in fact it doesn't work the way you expect and may produce panics in safe Rust:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=dd880f555dff38824b094dd8dec2f6f2

I'd better to be replaced with num_derive:

#[repr(u8)]
#[derive(Debug, Copy, Clone, FromPrimitive)]
pub enum MsgType {
@Pzixel
Copy link
Author

Pzixel commented Mar 15, 2019

Looks like it gonna be fixed by #63

@hdhoang
Copy link
Collaborator

hdhoang commented Mar 16, 2019

oh hey! thanks for your interest. We are very much interested in parsing the chip-to-chip message safely (#63 implements #20), but the struct-oriented scroll gave me some trouble with switching on enums. Your num_derive/num_traits suggestion might work very well indeed. I will give it a try, or maybe clone the trait into anne-key if it's no_std-incompatible.

@Pzixel
Copy link
Author

Pzixel commented Mar 16, 2019

Good to hear.

I've used scroll to parse ECMA335 CLI metadata and it worked fine for me. I'm surprised you have any troubles with it.

@hdhoang
Copy link
Collaborator

hdhoang commented Mar 19, 2019

My main trouble is that operation in MsgType is currently parsed as-needed, thus not buying much logic-safety over variant-casting. I'll look on crates.io and your code for examples too.

The good news is num-traits works just as you suggested, hooray!

@Pzixel
Copy link
Author

Pzixel commented Mar 19, 2019

You can express lazy parsing with any kind of Lazy<T> wrapper, if you wish. However, I don't see much troubles in one pattern match even if you don't need the result. It's very cheap after all, it doesn't make any heavy magic with strings or something.

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

No branches or pull requests

2 participants