Skip to content

Commit 57dfc4a

Browse files
committed
Fix unsoundness in Metadata union API
Closes rkyv#586 This is a breaking change, but is necessary for soundness. I doubt anyone is using this corner of the API in such a way that they can't fix any breakages themselves.
1 parent 276b196 commit 57dfc4a

4 files changed

Lines changed: 34 additions & 27 deletions

File tree

rkyv/src/de/pooling/mod.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,36 @@ impl<T: ?Sized> From<DynMetadata<T>> for Metadata {
5151
}
5252
}
5353

54+
/// A type which can be extracted from `Metadata`.
55+
pub trait FromMetadata {
56+
/// Extracts this type from [`Metadata`].
57+
///
58+
/// # Safety
59+
///
60+
/// The metadata must have been created by calling `Metadata::from` on a
61+
/// value of this type.
62+
unsafe fn from_metadata(metadata: Metadata) -> Self;
63+
}
64+
5465
// These impls are sound because `Metadata` has the type-level invariant that
5566
// `From` will only be called on `Metadata` created from pointers with the
5667
// corresponding metadata.
5768

58-
impl From<Metadata> for () {
59-
fn from(value: Metadata) -> Self {
60-
unsafe { value.unit }
69+
impl FromMetadata for () {
70+
unsafe fn from_metadata(metadata: Metadata) -> Self {
71+
unsafe { metadata.unit }
6172
}
6273
}
6374

64-
impl From<Metadata> for usize {
65-
fn from(value: Metadata) -> Self {
66-
unsafe { value.usize }
75+
impl FromMetadata for usize {
76+
unsafe fn from_metadata(metadata: Metadata) -> Self {
77+
unsafe { metadata.usize }
6778
}
6879
}
6980

70-
impl<T: ?Sized> From<Metadata> for DynMetadata<T> {
71-
fn from(value: Metadata) -> Self {
72-
unsafe { transmute::<DynMetadata<()>, DynMetadata<T>>(value.vtable) }
81+
impl<T: ?Sized> FromMetadata for DynMetadata<T> {
82+
unsafe fn from_metadata(metadata: Metadata) -> Self {
83+
unsafe { transmute::<DynMetadata<()>, DynMetadata<T>>(metadata.vtable) }
7384
}
7485
}
7586

@@ -107,9 +118,11 @@ impl ErasedPtr {
107118
unsafe fn downcast_unchecked<T>(&self) -> *mut T
108119
where
109120
T: Pointee + ?Sized,
110-
Metadata: Into<T::Metadata>,
121+
T::Metadata: FromMetadata,
111122
{
112-
from_raw_parts_mut(self.data_address.as_ptr(), self.metadata.into())
123+
from_raw_parts_mut(self.data_address.as_ptr(), unsafe {
124+
T::Metadata::from_metadata(self.metadata)
125+
})
113126
}
114127
}
115128

@@ -223,8 +236,7 @@ pub trait PoolingExt<E>: Pooling<E> {
223236
) -> Result<*mut T, Self::Error>
224237
where
225238
T: ArchiveUnsized + Pointee + LayoutRaw + ?Sized,
226-
T::Metadata: Into<Metadata>,
227-
Metadata: Into<T::Metadata>,
239+
T::Metadata: Into<Metadata> + FromMetadata,
228240
T::Archived: DeserializeUnsized<T, Self>,
229241
P: SharedPointer<T>,
230242
Self: Fallible<Error = E>,
@@ -233,7 +245,7 @@ pub trait PoolingExt<E>: Pooling<E> {
233245
unsafe fn drop_shared<T, P>(ptr: ErasedPtr)
234246
where
235247
T: Pointee + ?Sized,
236-
Metadata: Into<T::Metadata>,
248+
T::Metadata: FromMetadata,
237249
P: SharedPointer<T>,
238250
{
239251
unsafe { P::drop(ptr.downcast_unchecked::<T>()) }

rkyv/src/impls/alloc/rc/atomic.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rancor::{Fallible, Source};
55

66
use crate::{
77
alloc::{alloc::alloc, boxed::Box, sync},
8-
de::{Metadata, Pooling, PoolingExt as _, SharedPointer},
8+
de::{FromMetadata, Metadata, Pooling, PoolingExt as _, SharedPointer},
99
rc::{ArcFlavor, ArchivedRc, ArchivedRcWeak, RcResolver, RcWeakResolver},
1010
ser::{Sharing, Writer},
1111
traits::{ArchivePointee, LayoutRaw},
@@ -67,8 +67,7 @@ impl<T, D> Deserialize<sync::Arc<T>, D> for ArchivedRc<T::Archived, ArcFlavor>
6767
where
6868
T: ArchiveUnsized + LayoutRaw + Pointee + ?Sized + 'static,
6969
T::Archived: DeserializeUnsized<T, D>,
70-
T::Metadata: Into<Metadata>,
71-
Metadata: Into<T::Metadata>,
70+
T::Metadata: Into<Metadata> + FromMetadata,
7271
D: Fallible + Pooling + ?Sized,
7372
D::Error: Source,
7473
{
@@ -139,8 +138,7 @@ where
139138
+ Pointee // + ?Sized
140139
+ 'static,
141140
T::Archived: DeserializeUnsized<T, D>,
142-
T::Metadata: Into<Metadata>,
143-
Metadata: Into<T::Metadata>,
141+
T::Metadata: Into<Metadata> + FromMetadata,
144142
D: Fallible + Pooling + ?Sized,
145143
D::Error: Source,
146144
{

rkyv/src/impls/alloc/rc/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rancor::{Fallible, Source};
88

99
use crate::{
1010
alloc::{alloc::alloc, boxed::Box, rc},
11-
de::{Metadata, Pooling, PoolingExt as _, SharedPointer},
11+
de::{FromMetadata, Metadata, Pooling, PoolingExt as _, SharedPointer},
1212
rc::{ArchivedRc, ArchivedRcWeak, RcFlavor, RcResolver, RcWeakResolver},
1313
ser::{Sharing, Writer},
1414
traits::{ArchivePointee, LayoutRaw},
@@ -70,8 +70,7 @@ impl<T, D> Deserialize<rc::Rc<T>, D> for ArchivedRc<T::Archived, RcFlavor>
7070
where
7171
T: ArchiveUnsized + LayoutRaw + Pointee + ?Sized + 'static,
7272
T::Archived: DeserializeUnsized<T, D>,
73-
T::Metadata: Into<Metadata>,
74-
Metadata: Into<T::Metadata>,
73+
T::Metadata: Into<Metadata> + FromMetadata,
7574
D: Fallible + Pooling + ?Sized,
7675
D::Error: Source,
7776
{
@@ -136,8 +135,7 @@ where
136135
+ Pointee // + ?Sized
137136
+ 'static,
138137
T::Archived: DeserializeUnsized<T, D>,
139-
T::Metadata: Into<Metadata>,
140-
Metadata: Into<T::Metadata>,
138+
T::Metadata: Into<Metadata> + FromMetadata,
141139
D: Fallible + Pooling + ?Sized,
142140
D::Error: Source,
143141
{

rkyv/src/impls/ext/triomphe_0_1.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rancor::{Fallible, Source};
88
use triomphe_0_1::Arc;
99

1010
use crate::{
11-
de::{Metadata, Pooling, PoolingExt, SharedPointer},
11+
de::{FromMetadata, Metadata, Pooling, PoolingExt, SharedPointer},
1212
rc::{ArchivedRc, Flavor, RcResolver},
1313
ser::{Sharing, Writer},
1414
Archive, ArchiveUnsized, Deserialize, DeserializeUnsized, Place, Serialize,
@@ -66,8 +66,7 @@ where
6666
impl<T, D> Deserialize<Arc<T>, D> for ArchivedRc<T::Archived, TriompheArcFlavor>
6767
where
6868
T: ArchiveUnsized + 'static,
69-
T::Metadata: Into<Metadata>,
70-
Metadata: Into<T::Metadata>,
69+
T::Metadata: Into<Metadata> + FromMetadata,
7170
T::Archived: DeserializeUnsized<T, D>,
7271
D: Pooling + Fallible + ?Sized,
7372
D::Error: Source,

0 commit comments

Comments
 (0)