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

Add Thread::{into_raw, from_raw} #97524

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions library/std/src/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,54 @@ impl Thread {
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
}

/// Consumes the `Thread`, returning a raw pointer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to make the guarantees of this pointer more explicit, for example:

  • It can’t be round-tripped though &()
  • Any kind of reading or writing to the address of this pointer should be considered unsound
  • The pointer is not valid for anything other than Thread::from_raw

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can’t be round-tripped though &()

I don't think this should be documented here. Maybe it should go on the pointer type itself, because you should never expect to be able to round-trip a pointer to any type through a reference of any type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it would be fine to expect it for <NonNull<()>>::dangling(). But it’s still a fair point.

Copy link
Member

@saethlin saethlin May 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making the reference for that case is UB
(ah, of course it isn't in this specific case because this is a reference to a ZST)

///
/// To avoid a memory leak the pointer must be converted
/// back into a `Thread` using [`Thread::from_raw`].
///
/// # Examples
///
/// ```
/// #![feature(thread_raw)]
///
/// use std::thread::{self, Thread};
///
/// let thread = thread::current();
/// let id = thread.id();
/// let ptr = Thread::into_raw(thread);
/// unsafe {
/// assert_eq!(Thread::from_raw(ptr).id(), id);
/// }
/// ```
#[unstable(feature = "thread_raw", issue = "97523")]
pub fn into_raw(self) -> *const () {
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
Arc::into_raw(inner) as *const ()
}

/// Constructs a `Thread` from a raw pointer.
///
/// The raw pointer must have been previously returned
/// by a call to [`Thread::into_raw`].
///
/// # Safety
///
/// This function is unsafe because improper use may lead
/// to memory unsafety, even if the returned `Thread` is never
/// accessed.
///
/// Creating a `Thread` from a pointer other than one returned
/// from [`Thread::into_raw`] is **undefined behavior**.
///
/// Calling this function twice on the same raw pointer can lead
/// to a double-free if both `Thread` instances are dropped.
#[unstable(feature = "thread_raw", issue = "97523")]
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
// Safety: Upheld by caller.
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
}

fn cname(&self) -> Option<&CStr> {
self.inner.name.as_deref()
}
Expand Down
Loading