-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Tracking issue for std::ptr::NonNull::cast #47653
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
Would it be possible to add a |
How would that work? How does this method you pick a vtable or a slice length? The only way I know in safe Rust (other than ad-hoc APIs like #![feature(box_into_raw_non_null)]
use std::ptr::NonNull;
fn main() {
// Creating thin pointers
let a: NonNull<[u8; 10]> = Box::into_raw_non_null(Box::new([42; 10]));
let b: NonNull<String> = Box::into_raw_non_null(Box::new(String::new()));
// Coercing to fat pointers to dynamically-sized types
let _a: NonNull<[u8]> = a;
let _b: NonNull<std::fmt::Display> = b;
} |
I suppose I was thinking particularly about statically typed but dynamically sized fat pointers (e.g., to slices). I'm not sure how you'd answer the question about vtables. So, concretely, converting between, e.g., |
Turns out you can cast a raw slice to another. This leaves the length unchanged regardless of the item type, which is often wrong. For example, this compiles and prints random (stack?) memory. fn main() {
let b = [1, 2, 3, 4, 5];
let ptr = cast_slice::<u8, u64>(&b);
for x in unsafe { &*ptr } {
println!("{:016x}", x)
}
}
fn cast_slice<T, U>(s: *const [T]) -> *const [U] {
s as _
} However that’s the case where the types on both sides of |
Does that also work for structs with the last field as an unsized slice?
(On my phone; can't test)
…On Jan 22, 2018 1:39 AM, "Simon Sapin" ***@***.***> wrote:
Turns out you can cast a raw slice to another. This leaves the length
unchanged regardless of the item type, which is often wrong. For example,
this compiles and prints random (stack?) memory.
fn main() {
let b = [1, 2, 3, 4, 5];
let ptr = cast_slice::<u8, u64>(&b);
for x in unsafe { &*ptr } {
println!("{:016x}", x)
}
}
fn cast_slice<T, U>(s: *const [T]) -> *const [U] {
s as _
}
However that’s the case where the types on both sides of as are known to
be raw slices. In the fully-generic ?Sized case the compiler doesn’t know
what code to emit.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#47653 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA_2L_Rj579HpWdWeA2g0Hykoi51veOeks5tNFdKgaJpZM4RmTjN>
.
|
This compiles, however wrong it may be: fn main() {
struct Foo(u8, [u8]);
struct Bar(String, [u64]);
let ptr: *const Foo = unimplemented!();
ptr as *const Bar;
} But this is still slice to slice. If trait objects are involved, they need to be the same trait. At least that’s the current implementation of |
OK, probably worth it to just stick with |
This one-line method landed in Nightly on 2018-02-07. If stabilized in the current 1.26 cycle, it will reach Stable on 2018-05-11 after four months. @aturon, is this enough baking time to start FCP? |
#49669 adds a TR;DR: Despite limitations I think we should stabilize this as-is. @rfcbot fcp merge |
Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
stabilize a bunch of minor api additions besides `ptr::NonNull::cast` (which is 4 days away from end of FCP) all of these have been finished with FCP for a few weeks now with minimal issues raised * Closes #41020 * Closes #42818 * Closes #44030 * Closes #44400 * Closes #46507 * Closes #47653 * Closes #46344 the following functions will be stabilized in 1.27: * `[T]::rsplit` * `[T]::rsplit_mut` * `[T]::swap_with_slice` * `ptr::swap_nonoverlapping` * `NonNull::cast` * `Duration::from_micros` * `Duration::from_nanos` * `Duration::subsec_millis` * `Duration::subsec_micros` * `HashMap::remove_entry`
Ran into the issue where I can't cast between NonNull slice types. |
fn main() {
let a: *const [u8] = b"foo";
println!("{:04x?}", unsafe { &*(a as *const [u16]) })
} Playground, output:
The You can use |
I understand that you can do unsafe (and unsound) things when casting pointers. |
It’s already discussed above why we can’t just add |
That actually might be useful if only to give us a place to document the footgun that is casting slice pointers. Since it's a keyword, |
Yes, except I think it should just be called |
@joshlf rustdoc does support documenting keywords, these days: @jethrogb Re calling it |
Hmm I half-expected an impl coherence error, but this compiles. I’m not sure how I feel about potentially adding it to the standard library though. unsafe trait Cast<T: ?Sized> {
fn cast(ptr: *mut Self) -> *mut T;
}
// implied: T: Sized
unsafe impl<T, U: ?Sized> Cast<T> for U {
fn cast(ptr: *mut Self) -> *mut T {
ptr as _
}
}
unsafe impl<T, U> Cast<[T]> for [U] {
fn cast(slice: *mut Self) -> *mut [T] {
unsafe {
let ptr = (*slice).as_mut_ptr();
let len = (*slice).len();
std::slice::from_raw_parts_mut(ptr as _, len)
}
}
} |
No need for a trait: struct Ptr<T: ?Sized>(*const T);
impl<T> Ptr<T> {
fn cast<U>(self) -> Ptr<U> {
Ptr(self.0 as *const _)
}
}
impl<T> Ptr<[T]> {
fn cast<U>(self) -> Ptr<[U]> {
Ptr(self.0 as *const _)
}
} |
@jethrogb That code doesn’t have |
Yes, you're right, I didn't look at the docs in detail enough to see that existing bound |
ptr::NonNull<T>
is similar to*mut T
. Itscast
method added in #47631 is similar to raw pointer casting with theas
operator.Note that
T
is?Sized
butU
is not (or we’d get a E0606 "vtable kinds may not match" error onas
)The text was updated successfully, but these errors were encountered: