Hey, I've found this while scanning the top downloaded crates with my UB static analyzer.
src/ctl_type.rs:41:
impl std::convert::From<u32> for CtlType {
fn from(t: u32) -> Self {
assert!(t <= 16);
unsafe { std::mem::transmute(t) }
}
}
The guard allows 16, but discriminant 16 is Temperature, which only exists under #[cfg(target_os = "freebsd")]. On Linux or macOS the valid discriminants stop at 15, so CtlType::from(16) transmutes into a value the enum does not have. It is a safe public conversion, so safe code produces an invalid value.
#[test]
fn ctl_type_from_16_is_invalid_off_freebsd() {
let t = sysctl::CtlType::from(16u32);
let _ = format!("{:?}", t);
}
$ cargo +nightly miri test
test ctl_type_from_16_is_invalid_off_freebsd ... error: Undefined Behavior: constructing invalid value of type sysctl::CtlType: at .<enum-tag>, encountered 0x00000010, but expected a valid enum tag
--> sysctl-0.7.1/src/ctl_type.rs:44:18
|
44 | unsafe { std::mem::transmute(t) }
| ^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
Fix would be to put the bound behind the same cfg as the variant, so it is t <= 16 on FreeBSD and t <= 15 elsewhere. Better still, match on the value and return CtlType::None or an error for anything unknown, which drops the transmute entirely.
Hey, I've found this while scanning the top downloaded crates with my UB static analyzer.
src/ctl_type.rs:41:
The guard allows 16, but discriminant 16 is
Temperature, which only exists under#[cfg(target_os = "freebsd")]. On Linux or macOS the valid discriminants stop at 15, soCtlType::from(16)transmutes into a value the enum does not have. It is a safe public conversion, so safe code produces an invalid value.Fix would be to put the bound behind the same cfg as the variant, so it is
t <= 16on FreeBSD andt <= 15elsewhere. Better still, match on the value and returnCtlType::Noneor an error for anything unknown, which drops thetransmuteentirely.