-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
UncasedStr::new is undefined behavior #494
Comments
Same thing for these transmutes, which all assume
|
@dtolnay Is there definitive documentation about this? If the layout isn't guaranteed to be the same, why does Rust allow the |
I believe nomicon's Alternative representations is definitive.
|
Pointer casting is allowed across types that have a different layout but dereferencing the pointer is normally undefined. // Does not have the same layout as str.
struct Sergio {
repr: char,
}
fn main() {
let p: *const str = "C";
println!("{:p}", p as *const Sergio);
} |
FYI, struct Sergio {
repr: char,
}
fn main() {
let p = "C";
unsafe {
println!("{:p}", std::mem::transmute::<&str, &Sergio>(p)); // error[E0512]: transmute called with types of different sizes
}
} |
@dtolnay, @dmizuk Isn't the Looking at the std. library, it doesn't seem like In any case, here are the set of changes I have planned: --- a/lib/src/http/uncased.rs
+++ b/lib/src/http/uncased.rs
@@ -36,7 +36,7 @@ impl UncasedStr {
/// ```
#[inline(always)]
pub fn new(string: &str) -> &UncasedStr {
- unsafe { &*(string as *const str as *const UncasedStr) }
+ unsafe { ::std::mem::transmute(string) }
}
/// Returns `self` as an `&str`.
@@ -69,7 +69,7 @@ impl UncasedStr {
#[inline(always)]
pub fn into_uncased(self: Box<UncasedStr>) -> Uncased<'static> {
unsafe {
- let raw_str = Box::into_raw(self) as *mut str;
+ let raw_str: *mut str = ::std::mem::transmute(Box::into_raw(self));
Uncased::from(Box::from_raw(raw_str).into_string())
}
}
@@ -203,8 +203,9 @@ impl<'s> Uncased<'s> {
#[inline(always)]
pub fn into_boxed_uncased(self) -> Box<UncasedStr> {
unsafe {
- let raw_str = Box::into_raw(self.string.into_owned().into_boxed_str());
- Box::from_raw(raw_str as *mut UncasedStr)
+ let box_str = self.string.into_owned().into_boxed_str();
+ let raw: *mut UncasedStr = ::std::mem::transmute(Box::into_raw(box_str));
+ Box::from_raw(raw)
}
} Do these resolve the issue? |
The transmute checks that
My understanding is that the standard library is not beholden to the same soundness considerations that other libraries are. If the compiler makes a change that changes the layout of
I believe that is well defined. Note that without
Don't think so. Transmute vs pointer cast is a matter of preference I think, but whether the behavior is well defined is the same. I think the fix is adding |
For example I think it would be legal for a target to use a layout like this, to support better debugging or to compile for JVM or some other VM or any other reason. Here struct Newtype<T>(T);
But with |
I believe there is no guarantee that
str
andUncasedStr
have the same layout on all targets. From a discussion with @arielb1 at Rust Belt Rust aboutref-cast
, the behavior is only defined ifUncasedStr
is#[repr(C)]
.The text was updated successfully, but these errors were encountered: