Skip to content

Commit f8e6494

Browse files
committed
Auto merge of #99420 - RalfJung:vtable, r=oli-obk
make vtable pointers entirely opaque This implements the scheme discussed in rust-lang/unsafe-code-guidelines#338: vtable pointers should be considered entirely opaque and not even readable by Rust code, similar to function pointers. - We have a new kind of `GlobalAlloc` that symbolically refers to a vtable. - Miri uses that kind of allocation when generating a vtable. - The codegen backends, upon encountering such an allocation, call `vtable_allocation` to obtain an actually dataful allocation for this vtable. - We need new intrinsics to obtain the size and align from a vtable (for some `ptr::metadata` APIs), since direct accesses are UB now. I had to touch quite a bit of code that I am not very familiar with, so some of this might not make much sense... r? `@oli-obk`
2 parents 50e73b8 + b7022e7 commit f8e6494

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

core/src/intrinsics.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,6 +2291,16 @@ extern "rust-intrinsic" {
22912291
/// [`std::hint::black_box`]: crate::hint::black_box
22922292
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
22932293
pub fn black_box<T>(dummy: T) -> T;
2294+
2295+
/// `ptr` must point to a vtable.
2296+
/// The intrinsic will return the size stored in that vtable.
2297+
#[cfg(not(bootstrap))]
2298+
pub fn vtable_size(ptr: *const ()) -> usize;
2299+
2300+
/// `ptr` must point to a vtable.
2301+
/// The intrinsic will return the alignment stored in that vtable.
2302+
#[cfg(not(bootstrap))]
2303+
pub fn vtable_align(ptr: *const ()) -> usize;
22942304
}
22952305

22962306
// Some functions are defined here because they accidentally got made

core/src/ptr/metadata.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,20 @@ pub struct DynMetadata<Dyn: ?Sized> {
180180
phantom: crate::marker::PhantomData<Dyn>,
181181
}
182182

183+
#[cfg(not(bootstrap))]
184+
extern "C" {
185+
/// Opaque type for accessing vtables.
186+
///
187+
/// Private implementation detail of `DynMetadata::size_of` etc.
188+
/// There is conceptually not actually any Abstract Machine memory behind this pointer.
189+
type VTable;
190+
}
191+
183192
/// The common prefix of all vtables. It is followed by function pointers for trait methods.
184193
///
185194
/// Private implementation detail of `DynMetadata::size_of` etc.
186195
#[repr(C)]
196+
#[cfg(bootstrap)]
187197
struct VTable {
188198
drop_in_place: fn(*mut ()),
189199
size_of: usize,
@@ -194,13 +204,28 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
194204
/// Returns the size of the type associated with this vtable.
195205
#[inline]
196206
pub fn size_of(self) -> usize {
197-
self.vtable_ptr.size_of
207+
// Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw".
208+
// Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
209+
// `Send` part!
210+
#[cfg(bootstrap)]
211+
return self.vtable_ptr.size_of;
212+
#[cfg(not(bootstrap))]
213+
// SAFETY: DynMetadata always contains a valid vtable pointer
214+
return unsafe {
215+
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
216+
};
198217
}
199218

200219
/// Returns the alignment of the type associated with this vtable.
201220
#[inline]
202221
pub fn align_of(self) -> usize {
203-
self.vtable_ptr.align_of
222+
#[cfg(bootstrap)]
223+
return self.vtable_ptr.align_of;
224+
#[cfg(not(bootstrap))]
225+
// SAFETY: DynMetadata always contains a valid vtable pointer
226+
return unsafe {
227+
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
228+
};
204229
}
205230

206231
/// Returns the size and alignment together as a `Layout`

0 commit comments

Comments
 (0)