Skip to content

Commit b8178e9

Browse files
committed
libs: Add {Arc,Rc}::{from,into}_inner_raw, use them in std::thread internals
Fixes #224.
1 parent bc12232 commit b8178e9

File tree

5 files changed

+117
-5
lines changed

5 files changed

+117
-5
lines changed

libs/Patches.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,17 @@ into the main commit for that patch, and then the *Update* line can be removed.
269269
check if the pointer is not equal to each of the individual sentinel values.
270270
See also the "Avoid raw pointer comparisons" note below.
271271

272+
* Add `{Arc,Rc}::{from,inner}_into_raw` API functions (last applied: January 22, 2026)
273+
274+
`crucible-mir` is not currently able to simulate the
275+
`{Arc,Rc}::{from,inner}_raw` functions, as they rely on non-trivial pointer
276+
offsets plus read from type-casted pointers.
277+
`{Arc,Rc}::{from,inner}_into_raw` offer alternatives with very similar types,
278+
but which are implemented in a Crucible-friendly way. We use these functions
279+
in the internals of `std::thread`.
280+
281+
See also the "`{Arc,Rc}::{from,inner}_into_raw`" below.
282+
272283
# Notes
273284

274285
This section contains more detailed notes about why certain patches are written
@@ -325,3 +336,54 @@ Using the `PartialEq` impl for raw pointers works better in a `crucible-mir`
325336
context. Instead of raising a simulation error, `crucible-mir` will simply
326337
return `False` when checking if a `MirReference_Integer` is equal to a valid
327338
`MirReference`.
339+
340+
## `{Arc,Rc}::{from,into}_inner_raw`
341+
342+
`crucible-mir` is not currently able to simulate the
343+
`{Arc,Rc}::{from,into}_raw` functions. This is because they subtract a constant
344+
offset from a `*T` pointer in order to obtain a pointer of type
345+
`*ArcInner<T>`/`*RcInner<T>`. This sort of pointer arithmetic is permitted in
346+
Rust, but `crucible-mir`'s memory model is not yet sophisticated enough to
347+
support this.
348+
349+
As a workaround, we offer `{Arc,Rc}::{from,into}_inner_raw` API functions,
350+
which work directly on `*ArcInner<T>`/`*RcInner<T>` pointers instead of `*T`
351+
pointers, thereby avoiding the need for problematic pointer casts. This is not
352+
a perfect solution, as these functions will not work as drop-in replacements
353+
for `{Arc,Rc}::{from,into}_raw` in all situations due to the differences in
354+
types. Where they _do_ work as drop-in replacements are situations where a call
355+
to `{Arc,Rc}::into_raw` is followed by another call to `{Arc,Rc}::from_raw`,
356+
without reading the intermediate raw pointer in between. For instance, in the
357+
following example (taken from the [documentation for
358+
`Arc::from_raw`](https://doc.rust-lang.org/1.91.0/std/sync/struct.Arc.html#method.from_raw)):
359+
360+
```rs
361+
use std::sync::Arc;
362+
363+
let x = Arc::new("hello".to_owned());
364+
let x_ptr = Arc::into_raw(x);
365+
366+
unsafe {
367+
// Convert back to an `Arc` to prevent leak.
368+
let x = Arc::from_raw(x_ptr);
369+
assert_eq!(&*x, "hello");
370+
371+
// Further calls to `Arc::from_raw(x_ptr)` would be memory-unsafe.
372+
}
373+
```
374+
375+
The calls to `Arc::{from,into}_raw` can be replaced with
376+
`Arc::{from,into}_inner_raw` with no change in functionality. This sort of
377+
pattern occurs fairly often in practice, so it is worth having at least some
378+
support for it. For example, the internals of `std::thread` also construct
379+
`Arc` values in a very similar fashion, so we also patch `std::thread` to use
380+
`Arc::{from,into}_inner_raw`.
381+
382+
(An API design note: because `{Arc,Rc}::{from,into}_inner_raw` are exposed as
383+
part of the public API, we must also expose the (previously internal)
384+
`ArcInner` and `RcInner` types as a consequence.)
385+
386+
Once `crucible-mir` finishes migrating to use `MirAggregate` (see
387+
https://github.com/GaloisInc/crucible/issues/1499), it should be able to
388+
simulate `{Arc,Rc}::{from,into}_raw` properly, which would allow us to remove
389+
`{Arc,Rc}::{from,into}_inner_raw`.

libs/alloc/src/rc.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ use crate::vec::Vec;
278278
// would interfere with otherwise safe [into|from]_raw() of transmutable
279279
// inner types.
280280
#[repr(C)]
281-
struct RcInner<T: ?Sized> {
281+
#[stable(feature = "rc_raw", since = "1.17.0")]
282+
pub struct RcInner<T: ?Sized> {
282283
strong: Cell<usize>,
283284
weak: Cell<usize>,
284285
value: T,
@@ -1298,6 +1299,16 @@ impl<T: ?Sized> Rc<T> {
12981299
unsafe { Self::from_raw_in(ptr, Global) }
12991300
}
13001301

1302+
/// Like [`from_raw`], except that this function accepts an `RcInner<T>`
1303+
/// pointer instead of a `T` pointer. This is meant to serve as a
1304+
/// replacement for [`from_raw`] (to be used in conjunction with
1305+
/// [`into_inner_raw`]) that is feasible for `crucible-mir` to simulate.
1306+
#[inline]
1307+
#[stable(feature = "rc_raw", since = "1.17.0")]
1308+
pub unsafe fn from_inner_raw(ptr: *const RcInner<T>) -> Self {
1309+
unsafe { Rc::from_ptr(ptr as *mut RcInner<T>) }
1310+
}
1311+
13011312
/// Consumes the `Rc`, returning the wrapped pointer.
13021313
///
13031314
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -1322,6 +1333,18 @@ impl<T: ?Sized> Rc<T> {
13221333
Self::as_ptr(&*this)
13231334
}
13241335

1336+
/// Like [`into_raw`], except that this function returns an `RcInner<T>`
1337+
/// pointer instead of a `T` pointer. This is meant to serve as a
1338+
/// replacement for [`into_raw`] (to be used in conjunction with
1339+
/// [`from_inner_raw`]) that is feasible for `crucible-mir` to simulate.
1340+
#[must_use = "losing the pointer will leak memory"]
1341+
#[stable(feature = "rc_raw", since = "1.17.0")]
1342+
#[rustc_never_returns_null_ptr]
1343+
pub fn into_inner_raw(this: Self) -> *const RcInner<T> {
1344+
let this = ManuallyDrop::new(this);
1345+
this.ptr.as_ptr() as *const RcInner<T>
1346+
}
1347+
13251348
/// Increments the strong reference count on the `Rc<T>` associated with the
13261349
/// provided pointer by one.
13271350
///

libs/alloc/src/sync.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
367367
// would interfere with otherwise safe [into|from]_raw() of transmutable
368368
// inner types.
369369
#[repr(C)]
370-
struct ArcInner<T: ?Sized> {
370+
#[stable(feature = "rc_raw", since = "1.17.0")]
371+
pub struct ArcInner<T: ?Sized> {
371372
strong: Atomic<usize>,
372373

373374
// the value usize::MAX acts as a sentinel for temporarily "locking" the
@@ -387,7 +388,9 @@ fn arcinner_layout_for_value_layout(layout: Layout) -> Layout {
387388
Layout::new::<ArcInner<()>>().extend(layout).unwrap().0.pad_to_align()
388389
}
389390

391+
#[stable(feature = "rc_raw", since = "1.17.0")]
390392
unsafe impl<T: ?Sized + Sync + Send> Send for ArcInner<T> {}
393+
#[stable(feature = "rc_raw", since = "1.17.0")]
391394
unsafe impl<T: ?Sized + Sync + Send> Sync for ArcInner<T> {}
392395

393396
impl<T> Arc<T> {
@@ -1443,6 +1446,16 @@ impl<T: ?Sized> Arc<T> {
14431446
unsafe { Arc::from_raw_in(ptr, Global) }
14441447
}
14451448

1449+
/// Like [`from_raw`], except that this function accepts an `ArcInner<T>`
1450+
/// pointer instead of a `T` pointer. This is meant to serve as a
1451+
/// replacement for [`from_raw`] (to be used in conjunction with
1452+
/// [`into_inner_raw`]) that is feasible for `crucible-mir` to simulate.
1453+
#[inline]
1454+
#[stable(feature = "rc_raw", since = "1.17.0")]
1455+
pub unsafe fn from_inner_raw(ptr: *const ArcInner<T>) -> Self {
1456+
unsafe { Arc::from_ptr(ptr as *mut ArcInner<T>) }
1457+
}
1458+
14461459
/// Consumes the `Arc`, returning the wrapped pointer.
14471460
///
14481461
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
@@ -1467,6 +1480,18 @@ impl<T: ?Sized> Arc<T> {
14671480
Self::as_ptr(&*this)
14681481
}
14691482

1483+
/// Like [`into_raw`], except that this function returns an `ArcInner<T>`
1484+
/// pointer instead of a `T` pointer. This is meant to serve as a
1485+
/// replacement for [`into_raw`] (to be used in conjunction with
1486+
/// [`from_inner_raw`]) that is feasible for `crucible-mir` to simulate.
1487+
#[must_use = "losing the pointer will leak memory"]
1488+
#[stable(feature = "rc_raw", since = "1.17.0")]
1489+
#[rustc_never_returns_null_ptr]
1490+
pub fn into_inner_raw(this: Self) -> *const ArcInner<T> {
1491+
let this = ManuallyDrop::new(this);
1492+
this.ptr.as_ptr() as *const ArcInner<T>
1493+
}
1494+
14701495
/// Increments the strong reference count on the `Arc<T>` associated with the
14711496
/// provided pointer by one.
14721497
///

libs/std/src/sync/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ pub use core::sync::atomic;
180180
pub use alloc_crate::sync::UniqueArc;
181181
#[stable(feature = "rust1", since = "1.0.0")]
182182
pub use alloc_crate::sync::{Arc, Weak};
183+
#[stable(feature = "rc_raw", since = "1.17.0")]
184+
pub use alloc_crate::sync::ArcInner;
183185

184186
// FIXME(sync_nonpoison,sync_poison_mod): remove all `#[doc(inline)]` once the modules are stabilized.
185187

libs/std/src/thread/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ use crate::marker::PhantomData;
165165
use crate::mem::{self, ManuallyDrop, forget};
166166
use crate::num::NonZero;
167167
use crate::pin::Pin;
168-
use crate::sync::Arc;
168+
use crate::sync::{Arc, ArcInner};
169169
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
170170
use crate::sys::sync::Parker;
171171
use crate::sys::thread as imp;
@@ -1647,7 +1647,7 @@ impl Thread {
16471647
pub fn into_raw(self) -> *const () {
16481648
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
16491649
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
1650-
Arc::into_raw(inner) as *const ()
1650+
unsafe { Arc::into_inner_raw(inner) as *const () }
16511651
}
16521652

16531653
/// Constructs a `Thread` from a raw pointer.
@@ -1669,7 +1669,7 @@ impl Thread {
16691669
#[unstable(feature = "thread_raw", issue = "97523")]
16701670
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
16711671
// Safety: Upheld by caller.
1672-
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
1672+
unsafe { Thread { inner: Pin::new_unchecked(Arc::from_inner_raw(ptr as *const ArcInner<Inner>)) } }
16731673
}
16741674

16751675
fn cname(&self) -> Option<&CStr> {

0 commit comments

Comments
 (0)